core.py 284 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959
  1. """
  2. numpy.ma : a package to handle missing or invalid values.
  3. This package was initially written for numarray by Paul F. Dubois
  4. at Lawrence Livermore National Laboratory.
  5. In 2006, the package was completely rewritten by Pierre Gerard-Marchant
  6. (University of Georgia) to make the MaskedArray class a subclass of ndarray,
  7. and to improve support of structured arrays.
  8. Copyright 1999, 2000, 2001 Regents of the University of California.
  9. Released for unlimited redistribution.
  10. * Adapted for numpy_core 2005 by Travis Oliphant and (mainly) Paul Dubois.
  11. * Subclassing of the base `ndarray` 2006 by Pierre Gerard-Marchant
  12. (pgmdevlist_AT_gmail_DOT_com)
  13. * Improvements suggested by Reggie Dugard (reggie_AT_merfinllc_DOT_com)
  14. .. moduleauthor:: Pierre Gerard-Marchant
  15. """
  16. # pylint: disable-msg=E1002
  17. import builtins
  18. import functools
  19. import inspect
  20. import operator
  21. import warnings
  22. import textwrap
  23. import re
  24. from typing import Dict
  25. import numpy as np
  26. import numpy._core.umath as umath
  27. import numpy._core.numerictypes as ntypes
  28. from numpy._core import multiarray as mu
  29. from numpy import ndarray, amax, amin, iscomplexobj, bool_, _NoValue, angle
  30. from numpy import array as narray, expand_dims, iinfo, finfo
  31. from numpy._core.numeric import normalize_axis_tuple
  32. from numpy._utils._inspect import getargspec, formatargspec
  33. from numpy._utils import set_module
  34. __all__ = [
  35. 'MAError', 'MaskError', 'MaskType', 'MaskedArray', 'abs', 'absolute',
  36. 'add', 'all', 'allclose', 'allequal', 'alltrue', 'amax', 'amin',
  37. 'angle', 'anom', 'anomalies', 'any', 'append', 'arange', 'arccos',
  38. 'arccosh', 'arcsin', 'arcsinh', 'arctan', 'arctan2', 'arctanh',
  39. 'argmax', 'argmin', 'argsort', 'around', 'array', 'asanyarray',
  40. 'asarray', 'bitwise_and', 'bitwise_or', 'bitwise_xor', 'bool_', 'ceil',
  41. 'choose', 'clip', 'common_fill_value', 'compress', 'compressed',
  42. 'concatenate', 'conjugate', 'convolve', 'copy', 'correlate', 'cos', 'cosh',
  43. 'count', 'cumprod', 'cumsum', 'default_fill_value', 'diag', 'diagonal',
  44. 'diff', 'divide', 'empty', 'empty_like', 'equal', 'exp',
  45. 'expand_dims', 'fabs', 'filled', 'fix_invalid', 'flatten_mask',
  46. 'flatten_structured_array', 'floor', 'floor_divide', 'fmod',
  47. 'frombuffer', 'fromflex', 'fromfunction', 'getdata', 'getmask',
  48. 'getmaskarray', 'greater', 'greater_equal', 'harden_mask', 'hypot',
  49. 'identity', 'ids', 'indices', 'inner', 'innerproduct', 'isMA',
  50. 'isMaskedArray', 'is_mask', 'is_masked', 'isarray', 'left_shift',
  51. 'less', 'less_equal', 'log', 'log10', 'log2',
  52. 'logical_and', 'logical_not', 'logical_or', 'logical_xor', 'make_mask',
  53. 'make_mask_descr', 'make_mask_none', 'mask_or', 'masked',
  54. 'masked_array', 'masked_equal', 'masked_greater',
  55. 'masked_greater_equal', 'masked_inside', 'masked_invalid',
  56. 'masked_less', 'masked_less_equal', 'masked_not_equal',
  57. 'masked_object', 'masked_outside', 'masked_print_option',
  58. 'masked_singleton', 'masked_values', 'masked_where', 'max', 'maximum',
  59. 'maximum_fill_value', 'mean', 'min', 'minimum', 'minimum_fill_value',
  60. 'mod', 'multiply', 'mvoid', 'ndim', 'negative', 'nomask', 'nonzero',
  61. 'not_equal', 'ones', 'ones_like', 'outer', 'outerproduct', 'power', 'prod',
  62. 'product', 'ptp', 'put', 'putmask', 'ravel', 'remainder',
  63. 'repeat', 'reshape', 'resize', 'right_shift', 'round', 'round_',
  64. 'set_fill_value', 'shape', 'sin', 'sinh', 'size', 'soften_mask',
  65. 'sometrue', 'sort', 'sqrt', 'squeeze', 'std', 'subtract', 'sum',
  66. 'swapaxes', 'take', 'tan', 'tanh', 'trace', 'transpose', 'true_divide',
  67. 'var', 'where', 'zeros', 'zeros_like',
  68. ]
  69. MaskType = np.bool
  70. nomask = MaskType(0)
  71. class MaskedArrayFutureWarning(FutureWarning):
  72. pass
  73. def _deprecate_argsort_axis(arr):
  74. """
  75. Adjust the axis passed to argsort, warning if necessary
  76. Parameters
  77. ----------
  78. arr
  79. The array which argsort was called on
  80. np.ma.argsort has a long-term bug where the default of the axis argument
  81. is wrong (gh-8701), which now must be kept for backwards compatibility.
  82. Thankfully, this only makes a difference when arrays are 2- or more-
  83. dimensional, so we only need a warning then.
  84. """
  85. if arr.ndim <= 1:
  86. # no warning needed - but switch to -1 anyway, to avoid surprising
  87. # subclasses, which are more likely to implement scalar axes.
  88. return -1
  89. else:
  90. # 2017-04-11, Numpy 1.13.0, gh-8701: warn on axis default
  91. warnings.warn(
  92. "In the future the default for argsort will be axis=-1, not the "
  93. "current None, to match its documentation and np.argsort. "
  94. "Explicitly pass -1 or None to silence this warning.",
  95. MaskedArrayFutureWarning, stacklevel=3)
  96. return None
  97. def doc_note(initialdoc, note):
  98. """
  99. Adds a Notes section to an existing docstring.
  100. """
  101. if initialdoc is None:
  102. return
  103. if note is None:
  104. return initialdoc
  105. notesplit = re.split(r'\n\s*?Notes\n\s*?-----', inspect.cleandoc(initialdoc))
  106. notedoc = "\n\nNotes\n-----\n%s\n" % inspect.cleandoc(note)
  107. return ''.join(notesplit[:1] + [notedoc] + notesplit[1:])
  108. def get_object_signature(obj):
  109. """
  110. Get the signature from obj
  111. """
  112. try:
  113. sig = formatargspec(*getargspec(obj))
  114. except TypeError:
  115. sig = ''
  116. return sig
  117. ###############################################################################
  118. # Exceptions #
  119. ###############################################################################
  120. class MAError(Exception):
  121. """
  122. Class for masked array related errors.
  123. """
  124. pass
  125. class MaskError(MAError):
  126. """
  127. Class for mask related errors.
  128. """
  129. pass
  130. ###############################################################################
  131. # Filling options #
  132. ###############################################################################
  133. # b: boolean - c: complex - f: floats - i: integer - O: object - S: string
  134. default_filler = {'b': True,
  135. 'c': 1.e20 + 0.0j,
  136. 'f': 1.e20,
  137. 'i': 999999,
  138. 'O': '?',
  139. 'S': b'N/A',
  140. 'u': 999999,
  141. 'V': b'???',
  142. 'U': 'N/A'
  143. }
  144. # Add datetime64 and timedelta64 types
  145. for v in ["Y", "M", "W", "D", "h", "m", "s", "ms", "us", "ns", "ps",
  146. "fs", "as"]:
  147. default_filler["M8[" + v + "]"] = np.datetime64("NaT", v)
  148. default_filler["m8[" + v + "]"] = np.timedelta64("NaT", v)
  149. float_types_list = [np.half, np.single, np.double, np.longdouble,
  150. np.csingle, np.cdouble, np.clongdouble]
  151. _minvals: Dict[type, int] = {}
  152. _maxvals: Dict[type, int] = {}
  153. for sctype in ntypes.sctypeDict.values():
  154. scalar_dtype = np.dtype(sctype)
  155. if scalar_dtype.kind in "Mm":
  156. info = np.iinfo(np.int64)
  157. min_val, max_val = info.min + 1, info.max
  158. elif np.issubdtype(scalar_dtype, np.integer):
  159. info = np.iinfo(sctype)
  160. min_val, max_val = info.min, info.max
  161. elif np.issubdtype(scalar_dtype, np.floating):
  162. info = np.finfo(sctype)
  163. min_val, max_val = info.min, info.max
  164. elif scalar_dtype.kind == "b":
  165. min_val, max_val = 0, 1
  166. else:
  167. min_val, max_val = None, None
  168. _minvals[sctype] = min_val
  169. _maxvals[sctype] = max_val
  170. max_filler = _minvals
  171. max_filler.update([(k, -np.inf) for k in float_types_list[:4]])
  172. max_filler.update([(k, complex(-np.inf, -np.inf)) for k in float_types_list[-3:]])
  173. min_filler = _maxvals
  174. min_filler.update([(k, +np.inf) for k in float_types_list[:4]])
  175. min_filler.update([(k, complex(+np.inf, +np.inf)) for k in float_types_list[-3:]])
  176. del float_types_list
  177. def _recursive_fill_value(dtype, f):
  178. """
  179. Recursively produce a fill value for `dtype`, calling f on scalar dtypes
  180. """
  181. if dtype.names is not None:
  182. # We wrap into `array` here, which ensures we use NumPy cast rules
  183. # for integer casts, this allows the use of 99999 as a fill value
  184. # for int8.
  185. # TODO: This is probably a mess, but should best preserve behavior?
  186. vals = tuple(
  187. np.array(_recursive_fill_value(dtype[name], f))
  188. for name in dtype.names)
  189. return np.array(vals, dtype=dtype)[()] # decay to void scalar from 0d
  190. elif dtype.subdtype:
  191. subtype, shape = dtype.subdtype
  192. subval = _recursive_fill_value(subtype, f)
  193. return np.full(shape, subval)
  194. else:
  195. return f(dtype)
  196. def _get_dtype_of(obj):
  197. """ Convert the argument for *_fill_value into a dtype """
  198. if isinstance(obj, np.dtype):
  199. return obj
  200. elif hasattr(obj, 'dtype'):
  201. return obj.dtype
  202. else:
  203. return np.asanyarray(obj).dtype
  204. def default_fill_value(obj):
  205. """
  206. Return the default fill value for the argument object.
  207. The default filling value depends on the datatype of the input
  208. array or the type of the input scalar:
  209. ======== ========
  210. datatype default
  211. ======== ========
  212. bool True
  213. int 999999
  214. float 1.e20
  215. complex 1.e20+0j
  216. object '?'
  217. string 'N/A'
  218. ======== ========
  219. For structured types, a structured scalar is returned, with each field the
  220. default fill value for its type.
  221. For subarray types, the fill value is an array of the same size containing
  222. the default scalar fill value.
  223. Parameters
  224. ----------
  225. obj : ndarray, dtype or scalar
  226. The array data-type or scalar for which the default fill value
  227. is returned.
  228. Returns
  229. -------
  230. fill_value : scalar
  231. The default fill value.
  232. Examples
  233. --------
  234. >>> import numpy as np
  235. >>> np.ma.default_fill_value(1)
  236. 999999
  237. >>> np.ma.default_fill_value(np.array([1.1, 2., np.pi]))
  238. 1e+20
  239. >>> np.ma.default_fill_value(np.dtype(complex))
  240. (1e+20+0j)
  241. """
  242. def _scalar_fill_value(dtype):
  243. if dtype.kind in 'Mm':
  244. return default_filler.get(dtype.str[1:], '?')
  245. else:
  246. return default_filler.get(dtype.kind, '?')
  247. dtype = _get_dtype_of(obj)
  248. return _recursive_fill_value(dtype, _scalar_fill_value)
  249. def _extremum_fill_value(obj, extremum, extremum_name):
  250. def _scalar_fill_value(dtype):
  251. try:
  252. return extremum[dtype.type]
  253. except KeyError as e:
  254. raise TypeError(
  255. f"Unsuitable type {dtype} for calculating {extremum_name}."
  256. ) from None
  257. dtype = _get_dtype_of(obj)
  258. return _recursive_fill_value(dtype, _scalar_fill_value)
  259. def minimum_fill_value(obj):
  260. """
  261. Return the maximum value that can be represented by the dtype of an object.
  262. This function is useful for calculating a fill value suitable for
  263. taking the minimum of an array with a given dtype.
  264. Parameters
  265. ----------
  266. obj : ndarray, dtype or scalar
  267. An object that can be queried for it's numeric type.
  268. Returns
  269. -------
  270. val : scalar
  271. The maximum representable value.
  272. Raises
  273. ------
  274. TypeError
  275. If `obj` isn't a suitable numeric type.
  276. See Also
  277. --------
  278. maximum_fill_value : The inverse function.
  279. set_fill_value : Set the filling value of a masked array.
  280. MaskedArray.fill_value : Return current fill value.
  281. Examples
  282. --------
  283. >>> import numpy as np
  284. >>> import numpy.ma as ma
  285. >>> a = np.int8()
  286. >>> ma.minimum_fill_value(a)
  287. 127
  288. >>> a = np.int32()
  289. >>> ma.minimum_fill_value(a)
  290. 2147483647
  291. An array of numeric data can also be passed.
  292. >>> a = np.array([1, 2, 3], dtype=np.int8)
  293. >>> ma.minimum_fill_value(a)
  294. 127
  295. >>> a = np.array([1, 2, 3], dtype=np.float32)
  296. >>> ma.minimum_fill_value(a)
  297. inf
  298. """
  299. return _extremum_fill_value(obj, min_filler, "minimum")
  300. def maximum_fill_value(obj):
  301. """
  302. Return the minimum value that can be represented by the dtype of an object.
  303. This function is useful for calculating a fill value suitable for
  304. taking the maximum of an array with a given dtype.
  305. Parameters
  306. ----------
  307. obj : ndarray, dtype or scalar
  308. An object that can be queried for it's numeric type.
  309. Returns
  310. -------
  311. val : scalar
  312. The minimum representable value.
  313. Raises
  314. ------
  315. TypeError
  316. If `obj` isn't a suitable numeric type.
  317. See Also
  318. --------
  319. minimum_fill_value : The inverse function.
  320. set_fill_value : Set the filling value of a masked array.
  321. MaskedArray.fill_value : Return current fill value.
  322. Examples
  323. --------
  324. >>> import numpy as np
  325. >>> import numpy.ma as ma
  326. >>> a = np.int8()
  327. >>> ma.maximum_fill_value(a)
  328. -128
  329. >>> a = np.int32()
  330. >>> ma.maximum_fill_value(a)
  331. -2147483648
  332. An array of numeric data can also be passed.
  333. >>> a = np.array([1, 2, 3], dtype=np.int8)
  334. >>> ma.maximum_fill_value(a)
  335. -128
  336. >>> a = np.array([1, 2, 3], dtype=np.float32)
  337. >>> ma.maximum_fill_value(a)
  338. -inf
  339. """
  340. return _extremum_fill_value(obj, max_filler, "maximum")
  341. def _recursive_set_fill_value(fillvalue, dt):
  342. """
  343. Create a fill value for a structured dtype.
  344. Parameters
  345. ----------
  346. fillvalue : scalar or array_like
  347. Scalar or array representing the fill value. If it is of shorter
  348. length than the number of fields in dt, it will be resized.
  349. dt : dtype
  350. The structured dtype for which to create the fill value.
  351. Returns
  352. -------
  353. val : tuple
  354. A tuple of values corresponding to the structured fill value.
  355. """
  356. fillvalue = np.resize(fillvalue, len(dt.names))
  357. output_value = []
  358. for (fval, name) in zip(fillvalue, dt.names):
  359. cdtype = dt[name]
  360. if cdtype.subdtype:
  361. cdtype = cdtype.subdtype[0]
  362. if cdtype.names is not None:
  363. output_value.append(tuple(_recursive_set_fill_value(fval, cdtype)))
  364. else:
  365. output_value.append(np.array(fval, dtype=cdtype).item())
  366. return tuple(output_value)
  367. def _check_fill_value(fill_value, ndtype):
  368. """
  369. Private function validating the given `fill_value` for the given dtype.
  370. If fill_value is None, it is set to the default corresponding to the dtype.
  371. If fill_value is not None, its value is forced to the given dtype.
  372. The result is always a 0d array.
  373. """
  374. ndtype = np.dtype(ndtype)
  375. if fill_value is None:
  376. fill_value = default_fill_value(ndtype)
  377. # TODO: It seems better to always store a valid fill_value, the oddity
  378. # about is that `_fill_value = None` would behave even more
  379. # different then.
  380. # (e.g. this allows arr_uint8.astype(int64) to have the default
  381. # fill value again...)
  382. # The one thing that changed in 2.0/2.1 around cast safety is that the
  383. # default `int(99...)` is not a same-kind cast anymore, so if we
  384. # have a uint, use the default uint.
  385. if ndtype.kind == "u":
  386. fill_value = np.uint(fill_value)
  387. elif ndtype.names is not None:
  388. if isinstance(fill_value, (ndarray, np.void)):
  389. try:
  390. fill_value = np.asarray(fill_value, dtype=ndtype)
  391. except ValueError as e:
  392. err_msg = "Unable to transform %s to dtype %s"
  393. raise ValueError(err_msg % (fill_value, ndtype)) from e
  394. else:
  395. fill_value = np.asarray(fill_value, dtype=object)
  396. fill_value = np.array(_recursive_set_fill_value(fill_value, ndtype),
  397. dtype=ndtype)
  398. else:
  399. if isinstance(fill_value, str) and (ndtype.char not in 'OSVU'):
  400. # Note this check doesn't work if fill_value is not a scalar
  401. err_msg = "Cannot set fill value of string with array of dtype %s"
  402. raise TypeError(err_msg % ndtype)
  403. else:
  404. # In case we want to convert 1e20 to int.
  405. # Also in case of converting string arrays.
  406. try:
  407. fill_value = np.asarray(fill_value, dtype=ndtype)
  408. except (OverflowError, ValueError) as e:
  409. # Raise TypeError instead of OverflowError or ValueError.
  410. # OverflowError is seldom used, and the real problem here is
  411. # that the passed fill_value is not compatible with the ndtype.
  412. err_msg = "Cannot convert fill_value %s to dtype %s"
  413. raise TypeError(err_msg % (fill_value, ndtype)) from e
  414. return np.array(fill_value)
  415. def set_fill_value(a, fill_value):
  416. """
  417. Set the filling value of a, if a is a masked array.
  418. This function changes the fill value of the masked array `a` in place.
  419. If `a` is not a masked array, the function returns silently, without
  420. doing anything.
  421. Parameters
  422. ----------
  423. a : array_like
  424. Input array.
  425. fill_value : dtype
  426. Filling value. A consistency test is performed to make sure
  427. the value is compatible with the dtype of `a`.
  428. Returns
  429. -------
  430. None
  431. Nothing returned by this function.
  432. See Also
  433. --------
  434. maximum_fill_value : Return the default fill value for a dtype.
  435. MaskedArray.fill_value : Return current fill value.
  436. MaskedArray.set_fill_value : Equivalent method.
  437. Examples
  438. --------
  439. >>> import numpy as np
  440. >>> import numpy.ma as ma
  441. >>> a = np.arange(5)
  442. >>> a
  443. array([0, 1, 2, 3, 4])
  444. >>> a = ma.masked_where(a < 3, a)
  445. >>> a
  446. masked_array(data=[--, --, --, 3, 4],
  447. mask=[ True, True, True, False, False],
  448. fill_value=999999)
  449. >>> ma.set_fill_value(a, -999)
  450. >>> a
  451. masked_array(data=[--, --, --, 3, 4],
  452. mask=[ True, True, True, False, False],
  453. fill_value=-999)
  454. Nothing happens if `a` is not a masked array.
  455. >>> a = list(range(5))
  456. >>> a
  457. [0, 1, 2, 3, 4]
  458. >>> ma.set_fill_value(a, 100)
  459. >>> a
  460. [0, 1, 2, 3, 4]
  461. >>> a = np.arange(5)
  462. >>> a
  463. array([0, 1, 2, 3, 4])
  464. >>> ma.set_fill_value(a, 100)
  465. >>> a
  466. array([0, 1, 2, 3, 4])
  467. """
  468. if isinstance(a, MaskedArray):
  469. a.set_fill_value(fill_value)
  470. return
  471. def get_fill_value(a):
  472. """
  473. Return the filling value of a, if any. Otherwise, returns the
  474. default filling value for that type.
  475. """
  476. if isinstance(a, MaskedArray):
  477. result = a.fill_value
  478. else:
  479. result = default_fill_value(a)
  480. return result
  481. def common_fill_value(a, b):
  482. """
  483. Return the common filling value of two masked arrays, if any.
  484. If ``a.fill_value == b.fill_value``, return the fill value,
  485. otherwise return None.
  486. Parameters
  487. ----------
  488. a, b : MaskedArray
  489. The masked arrays for which to compare fill values.
  490. Returns
  491. -------
  492. fill_value : scalar or None
  493. The common fill value, or None.
  494. Examples
  495. --------
  496. >>> import numpy as np
  497. >>> x = np.ma.array([0, 1.], fill_value=3)
  498. >>> y = np.ma.array([0, 1.], fill_value=3)
  499. >>> np.ma.common_fill_value(x, y)
  500. 3.0
  501. """
  502. t1 = get_fill_value(a)
  503. t2 = get_fill_value(b)
  504. if t1 == t2:
  505. return t1
  506. return None
  507. def filled(a, fill_value=None):
  508. """
  509. Return input as an `~numpy.ndarray`, with masked values replaced by
  510. `fill_value`.
  511. If `a` is not a `MaskedArray`, `a` itself is returned.
  512. If `a` is a `MaskedArray` with no masked values, then ``a.data`` is
  513. returned.
  514. If `a` is a `MaskedArray` and `fill_value` is None, `fill_value` is set to
  515. ``a.fill_value``.
  516. Parameters
  517. ----------
  518. a : MaskedArray or array_like
  519. An input object.
  520. fill_value : array_like, optional.
  521. Can be scalar or non-scalar. If non-scalar, the
  522. resulting filled array should be broadcastable
  523. over input array. Default is None.
  524. Returns
  525. -------
  526. a : ndarray
  527. The filled array.
  528. See Also
  529. --------
  530. compressed
  531. Examples
  532. --------
  533. >>> import numpy as np
  534. >>> import numpy.ma as ma
  535. >>> x = ma.array(np.arange(9).reshape(3, 3), mask=[[1, 0, 0],
  536. ... [1, 0, 0],
  537. ... [0, 0, 0]])
  538. >>> x.filled()
  539. array([[999999, 1, 2],
  540. [999999, 4, 5],
  541. [ 6, 7, 8]])
  542. >>> x.filled(fill_value=333)
  543. array([[333, 1, 2],
  544. [333, 4, 5],
  545. [ 6, 7, 8]])
  546. >>> x.filled(fill_value=np.arange(3))
  547. array([[0, 1, 2],
  548. [0, 4, 5],
  549. [6, 7, 8]])
  550. """
  551. if hasattr(a, 'filled'):
  552. return a.filled(fill_value)
  553. elif isinstance(a, ndarray):
  554. # Should we check for contiguity ? and a.flags['CONTIGUOUS']:
  555. return a
  556. elif isinstance(a, dict):
  557. return np.array(a, 'O')
  558. else:
  559. return np.array(a)
  560. def get_masked_subclass(*arrays):
  561. """
  562. Return the youngest subclass of MaskedArray from a list of (masked) arrays.
  563. In case of siblings, the first listed takes over.
  564. """
  565. if len(arrays) == 1:
  566. arr = arrays[0]
  567. if isinstance(arr, MaskedArray):
  568. rcls = type(arr)
  569. else:
  570. rcls = MaskedArray
  571. else:
  572. arrcls = [type(a) for a in arrays]
  573. rcls = arrcls[0]
  574. if not issubclass(rcls, MaskedArray):
  575. rcls = MaskedArray
  576. for cls in arrcls[1:]:
  577. if issubclass(cls, rcls):
  578. rcls = cls
  579. # Don't return MaskedConstant as result: revert to MaskedArray
  580. if rcls.__name__ == 'MaskedConstant':
  581. return MaskedArray
  582. return rcls
  583. def getdata(a, subok=True):
  584. """
  585. Return the data of a masked array as an ndarray.
  586. Return the data of `a` (if any) as an ndarray if `a` is a ``MaskedArray``,
  587. else return `a` as a ndarray or subclass (depending on `subok`) if not.
  588. Parameters
  589. ----------
  590. a : array_like
  591. Input ``MaskedArray``, alternatively a ndarray or a subclass thereof.
  592. subok : bool
  593. Whether to force the output to be a `pure` ndarray (False) or to
  594. return a subclass of ndarray if appropriate (True, default).
  595. See Also
  596. --------
  597. getmask : Return the mask of a masked array, or nomask.
  598. getmaskarray : Return the mask of a masked array, or full array of False.
  599. Examples
  600. --------
  601. >>> import numpy as np
  602. >>> import numpy.ma as ma
  603. >>> a = ma.masked_equal([[1,2],[3,4]], 2)
  604. >>> a
  605. masked_array(
  606. data=[[1, --],
  607. [3, 4]],
  608. mask=[[False, True],
  609. [False, False]],
  610. fill_value=2)
  611. >>> ma.getdata(a)
  612. array([[1, 2],
  613. [3, 4]])
  614. Equivalently use the ``MaskedArray`` `data` attribute.
  615. >>> a.data
  616. array([[1, 2],
  617. [3, 4]])
  618. """
  619. try:
  620. data = a._data
  621. except AttributeError:
  622. data = np.array(a, copy=None, subok=subok)
  623. if not subok:
  624. return data.view(ndarray)
  625. return data
  626. get_data = getdata
  627. def fix_invalid(a, mask=nomask, copy=True, fill_value=None):
  628. """
  629. Return input with invalid data masked and replaced by a fill value.
  630. Invalid data means values of `nan`, `inf`, etc.
  631. Parameters
  632. ----------
  633. a : array_like
  634. Input array, a (subclass of) ndarray.
  635. mask : sequence, optional
  636. Mask. Must be convertible to an array of booleans with the same
  637. shape as `data`. True indicates a masked (i.e. invalid) data.
  638. copy : bool, optional
  639. Whether to use a copy of `a` (True) or to fix `a` in place (False).
  640. Default is True.
  641. fill_value : scalar, optional
  642. Value used for fixing invalid data. Default is None, in which case
  643. the ``a.fill_value`` is used.
  644. Returns
  645. -------
  646. b : MaskedArray
  647. The input array with invalid entries fixed.
  648. Notes
  649. -----
  650. A copy is performed by default.
  651. Examples
  652. --------
  653. >>> import numpy as np
  654. >>> x = np.ma.array([1., -1, np.nan, np.inf], mask=[1] + [0]*3)
  655. >>> x
  656. masked_array(data=[--, -1.0, nan, inf],
  657. mask=[ True, False, False, False],
  658. fill_value=1e+20)
  659. >>> np.ma.fix_invalid(x)
  660. masked_array(data=[--, -1.0, --, --],
  661. mask=[ True, False, True, True],
  662. fill_value=1e+20)
  663. >>> fixed = np.ma.fix_invalid(x)
  664. >>> fixed.data
  665. array([ 1.e+00, -1.e+00, 1.e+20, 1.e+20])
  666. >>> x.data
  667. array([ 1., -1., nan, inf])
  668. """
  669. a = masked_array(a, copy=copy, mask=mask, subok=True)
  670. invalid = np.logical_not(np.isfinite(a._data))
  671. if not invalid.any():
  672. return a
  673. a._mask |= invalid
  674. if fill_value is None:
  675. fill_value = a.fill_value
  676. a._data[invalid] = fill_value
  677. return a
  678. def is_string_or_list_of_strings(val):
  679. return (isinstance(val, str) or
  680. (isinstance(val, list) and val and
  681. builtins.all(isinstance(s, str) for s in val)))
  682. ###############################################################################
  683. # Ufuncs #
  684. ###############################################################################
  685. ufunc_domain = {}
  686. ufunc_fills = {}
  687. class _DomainCheckInterval:
  688. """
  689. Define a valid interval, so that :
  690. ``domain_check_interval(a,b)(x) == True`` where
  691. ``x < a`` or ``x > b``.
  692. """
  693. def __init__(self, a, b):
  694. "domain_check_interval(a,b)(x) = true where x < a or y > b"
  695. if a > b:
  696. (a, b) = (b, a)
  697. self.a = a
  698. self.b = b
  699. def __call__(self, x):
  700. "Execute the call behavior."
  701. # nans at masked positions cause RuntimeWarnings, even though
  702. # they are masked. To avoid this we suppress warnings.
  703. with np.errstate(invalid='ignore'):
  704. return umath.logical_or(umath.greater(x, self.b),
  705. umath.less(x, self.a))
  706. class _DomainTan:
  707. """
  708. Define a valid interval for the `tan` function, so that:
  709. ``domain_tan(eps) = True`` where ``abs(cos(x)) < eps``
  710. """
  711. def __init__(self, eps):
  712. "domain_tan(eps) = true where abs(cos(x)) < eps)"
  713. self.eps = eps
  714. def __call__(self, x):
  715. "Executes the call behavior."
  716. with np.errstate(invalid='ignore'):
  717. return umath.less(umath.absolute(umath.cos(x)), self.eps)
  718. class _DomainSafeDivide:
  719. """
  720. Define a domain for safe division.
  721. """
  722. def __init__(self, tolerance=None):
  723. self.tolerance = tolerance
  724. def __call__(self, a, b):
  725. # Delay the selection of the tolerance to here in order to reduce numpy
  726. # import times. The calculation of these parameters is a substantial
  727. # component of numpy's import time.
  728. if self.tolerance is None:
  729. self.tolerance = np.finfo(float).tiny
  730. # don't call ma ufuncs from __array_wrap__ which would fail for scalars
  731. a, b = np.asarray(a), np.asarray(b)
  732. with np.errstate(all='ignore'):
  733. return umath.absolute(a) * self.tolerance >= umath.absolute(b)
  734. class _DomainGreater:
  735. """
  736. DomainGreater(v)(x) is True where x <= v.
  737. """
  738. def __init__(self, critical_value):
  739. "DomainGreater(v)(x) = true where x <= v"
  740. self.critical_value = critical_value
  741. def __call__(self, x):
  742. "Executes the call behavior."
  743. with np.errstate(invalid='ignore'):
  744. return umath.less_equal(x, self.critical_value)
  745. class _DomainGreaterEqual:
  746. """
  747. DomainGreaterEqual(v)(x) is True where x < v.
  748. """
  749. def __init__(self, critical_value):
  750. "DomainGreaterEqual(v)(x) = true where x < v"
  751. self.critical_value = critical_value
  752. def __call__(self, x):
  753. "Executes the call behavior."
  754. with np.errstate(invalid='ignore'):
  755. return umath.less(x, self.critical_value)
  756. class _MaskedUFunc:
  757. def __init__(self, ufunc):
  758. self.f = ufunc
  759. self.__doc__ = ufunc.__doc__
  760. self.__name__ = ufunc.__name__
  761. self.__qualname__ = ufunc.__qualname__
  762. def __str__(self):
  763. return f"Masked version of {self.f}"
  764. class _MaskedUnaryOperation(_MaskedUFunc):
  765. """
  766. Defines masked version of unary operations, where invalid values are
  767. pre-masked.
  768. Parameters
  769. ----------
  770. mufunc : callable
  771. The function for which to define a masked version. Made available
  772. as ``_MaskedUnaryOperation.f``.
  773. fill : scalar, optional
  774. Filling value, default is 0.
  775. domain : class instance
  776. Domain for the function. Should be one of the ``_Domain*``
  777. classes. Default is None.
  778. """
  779. def __init__(self, mufunc, fill=0, domain=None):
  780. super().__init__(mufunc)
  781. self.fill = fill
  782. self.domain = domain
  783. ufunc_domain[mufunc] = domain
  784. ufunc_fills[mufunc] = fill
  785. def __call__(self, a, *args, **kwargs):
  786. """
  787. Execute the call behavior.
  788. """
  789. d = getdata(a)
  790. # Deal with domain
  791. if self.domain is not None:
  792. # Case 1.1. : Domained function
  793. # nans at masked positions cause RuntimeWarnings, even though
  794. # they are masked. To avoid this we suppress warnings.
  795. with np.errstate(divide='ignore', invalid='ignore'):
  796. result = self.f(d, *args, **kwargs)
  797. # Make a mask
  798. m = ~umath.isfinite(result)
  799. m |= self.domain(d)
  800. m |= getmask(a)
  801. else:
  802. # Case 1.2. : Function without a domain
  803. # Get the result and the mask
  804. with np.errstate(divide='ignore', invalid='ignore'):
  805. result = self.f(d, *args, **kwargs)
  806. m = getmask(a)
  807. if not result.ndim:
  808. # Case 2.1. : The result is scalarscalar
  809. if m:
  810. return masked
  811. return result
  812. if m is not nomask:
  813. # Case 2.2. The result is an array
  814. # We need to fill the invalid data back w/ the input Now,
  815. # that's plain silly: in C, we would just skip the element and
  816. # keep the original, but we do have to do it that way in Python
  817. # In case result has a lower dtype than the inputs (as in
  818. # equal)
  819. try:
  820. np.copyto(result, d, where=m)
  821. except TypeError:
  822. pass
  823. # Transform to
  824. masked_result = result.view(get_masked_subclass(a))
  825. masked_result._mask = m
  826. masked_result._update_from(a)
  827. return masked_result
  828. class _MaskedBinaryOperation(_MaskedUFunc):
  829. """
  830. Define masked version of binary operations, where invalid
  831. values are pre-masked.
  832. Parameters
  833. ----------
  834. mbfunc : function
  835. The function for which to define a masked version. Made available
  836. as ``_MaskedBinaryOperation.f``.
  837. domain : class instance
  838. Default domain for the function. Should be one of the ``_Domain*``
  839. classes. Default is None.
  840. fillx : scalar, optional
  841. Filling value for the first argument, default is 0.
  842. filly : scalar, optional
  843. Filling value for the second argument, default is 0.
  844. """
  845. def __init__(self, mbfunc, fillx=0, filly=0):
  846. """
  847. abfunc(fillx, filly) must be defined.
  848. abfunc(x, filly) = x for all x to enable reduce.
  849. """
  850. super().__init__(mbfunc)
  851. self.fillx = fillx
  852. self.filly = filly
  853. ufunc_domain[mbfunc] = None
  854. ufunc_fills[mbfunc] = (fillx, filly)
  855. def __call__(self, a, b, *args, **kwargs):
  856. """
  857. Execute the call behavior.
  858. """
  859. # Get the data, as ndarray
  860. (da, db) = (getdata(a), getdata(b))
  861. # Get the result
  862. with np.errstate():
  863. np.seterr(divide='ignore', invalid='ignore')
  864. result = self.f(da, db, *args, **kwargs)
  865. # Get the mask for the result
  866. (ma, mb) = (getmask(a), getmask(b))
  867. if ma is nomask:
  868. if mb is nomask:
  869. m = nomask
  870. else:
  871. m = umath.logical_or(getmaskarray(a), mb)
  872. elif mb is nomask:
  873. m = umath.logical_or(ma, getmaskarray(b))
  874. else:
  875. m = umath.logical_or(ma, mb)
  876. # Case 1. : scalar
  877. if not result.ndim:
  878. if m:
  879. return masked
  880. return result
  881. # Case 2. : array
  882. # Revert result to da where masked
  883. if m is not nomask and m.any():
  884. # any errors, just abort; impossible to guarantee masked values
  885. try:
  886. np.copyto(result, da, casting='unsafe', where=m)
  887. except Exception:
  888. pass
  889. # Transforms to a (subclass of) MaskedArray
  890. masked_result = result.view(get_masked_subclass(a, b))
  891. masked_result._mask = m
  892. if isinstance(a, MaskedArray):
  893. masked_result._update_from(a)
  894. elif isinstance(b, MaskedArray):
  895. masked_result._update_from(b)
  896. return masked_result
  897. def reduce(self, target, axis=0, dtype=None):
  898. """
  899. Reduce `target` along the given `axis`.
  900. """
  901. tclass = get_masked_subclass(target)
  902. m = getmask(target)
  903. t = filled(target, self.filly)
  904. if t.shape == ():
  905. t = t.reshape(1)
  906. if m is not nomask:
  907. m = make_mask(m, copy=True)
  908. m.shape = (1,)
  909. if m is nomask:
  910. tr = self.f.reduce(t, axis)
  911. mr = nomask
  912. else:
  913. tr = self.f.reduce(t, axis, dtype=dtype)
  914. mr = umath.logical_and.reduce(m, axis)
  915. if not tr.shape:
  916. if mr:
  917. return masked
  918. else:
  919. return tr
  920. masked_tr = tr.view(tclass)
  921. masked_tr._mask = mr
  922. return masked_tr
  923. def outer(self, a, b):
  924. """
  925. Return the function applied to the outer product of a and b.
  926. """
  927. (da, db) = (getdata(a), getdata(b))
  928. d = self.f.outer(da, db)
  929. ma = getmask(a)
  930. mb = getmask(b)
  931. if ma is nomask and mb is nomask:
  932. m = nomask
  933. else:
  934. ma = getmaskarray(a)
  935. mb = getmaskarray(b)
  936. m = umath.logical_or.outer(ma, mb)
  937. if (not m.ndim) and m:
  938. return masked
  939. if m is not nomask:
  940. np.copyto(d, da, where=m)
  941. if not d.shape:
  942. return d
  943. masked_d = d.view(get_masked_subclass(a, b))
  944. masked_d._mask = m
  945. return masked_d
  946. def accumulate(self, target, axis=0):
  947. """Accumulate `target` along `axis` after filling with y fill
  948. value.
  949. """
  950. tclass = get_masked_subclass(target)
  951. t = filled(target, self.filly)
  952. result = self.f.accumulate(t, axis)
  953. masked_result = result.view(tclass)
  954. return masked_result
  955. class _DomainedBinaryOperation(_MaskedUFunc):
  956. """
  957. Define binary operations that have a domain, like divide.
  958. They have no reduce, outer or accumulate.
  959. Parameters
  960. ----------
  961. mbfunc : function
  962. The function for which to define a masked version. Made available
  963. as ``_DomainedBinaryOperation.f``.
  964. domain : class instance
  965. Default domain for the function. Should be one of the ``_Domain*``
  966. classes.
  967. fillx : scalar, optional
  968. Filling value for the first argument, default is 0.
  969. filly : scalar, optional
  970. Filling value for the second argument, default is 0.
  971. """
  972. def __init__(self, dbfunc, domain, fillx=0, filly=0):
  973. """abfunc(fillx, filly) must be defined.
  974. abfunc(x, filly) = x for all x to enable reduce.
  975. """
  976. super().__init__(dbfunc)
  977. self.domain = domain
  978. self.fillx = fillx
  979. self.filly = filly
  980. ufunc_domain[dbfunc] = domain
  981. ufunc_fills[dbfunc] = (fillx, filly)
  982. def __call__(self, a, b, *args, **kwargs):
  983. "Execute the call behavior."
  984. # Get the data
  985. (da, db) = (getdata(a), getdata(b))
  986. # Get the result
  987. with np.errstate(divide='ignore', invalid='ignore'):
  988. result = self.f(da, db, *args, **kwargs)
  989. # Get the mask as a combination of the source masks and invalid
  990. m = ~umath.isfinite(result)
  991. m |= getmask(a)
  992. m |= getmask(b)
  993. # Apply the domain
  994. domain = ufunc_domain.get(self.f, None)
  995. if domain is not None:
  996. m |= domain(da, db)
  997. # Take care of the scalar case first
  998. if not m.ndim:
  999. if m:
  1000. return masked
  1001. else:
  1002. return result
  1003. # When the mask is True, put back da if possible
  1004. # any errors, just abort; impossible to guarantee masked values
  1005. try:
  1006. np.copyto(result, 0, casting='unsafe', where=m)
  1007. # avoid using "*" since this may be overlaid
  1008. masked_da = umath.multiply(m, da)
  1009. # only add back if it can be cast safely
  1010. if np.can_cast(masked_da.dtype, result.dtype, casting='safe'):
  1011. result += masked_da
  1012. except Exception:
  1013. pass
  1014. # Transforms to a (subclass of) MaskedArray
  1015. masked_result = result.view(get_masked_subclass(a, b))
  1016. masked_result._mask = m
  1017. if isinstance(a, MaskedArray):
  1018. masked_result._update_from(a)
  1019. elif isinstance(b, MaskedArray):
  1020. masked_result._update_from(b)
  1021. return masked_result
  1022. # Unary ufuncs
  1023. exp = _MaskedUnaryOperation(umath.exp)
  1024. conjugate = _MaskedUnaryOperation(umath.conjugate)
  1025. sin = _MaskedUnaryOperation(umath.sin)
  1026. cos = _MaskedUnaryOperation(umath.cos)
  1027. arctan = _MaskedUnaryOperation(umath.arctan)
  1028. arcsinh = _MaskedUnaryOperation(umath.arcsinh)
  1029. sinh = _MaskedUnaryOperation(umath.sinh)
  1030. cosh = _MaskedUnaryOperation(umath.cosh)
  1031. tanh = _MaskedUnaryOperation(umath.tanh)
  1032. abs = absolute = _MaskedUnaryOperation(umath.absolute)
  1033. angle = _MaskedUnaryOperation(angle)
  1034. fabs = _MaskedUnaryOperation(umath.fabs)
  1035. negative = _MaskedUnaryOperation(umath.negative)
  1036. floor = _MaskedUnaryOperation(umath.floor)
  1037. ceil = _MaskedUnaryOperation(umath.ceil)
  1038. around = _MaskedUnaryOperation(np.around)
  1039. logical_not = _MaskedUnaryOperation(umath.logical_not)
  1040. # Domained unary ufuncs
  1041. sqrt = _MaskedUnaryOperation(umath.sqrt, 0.0,
  1042. _DomainGreaterEqual(0.0))
  1043. log = _MaskedUnaryOperation(umath.log, 1.0,
  1044. _DomainGreater(0.0))
  1045. log2 = _MaskedUnaryOperation(umath.log2, 1.0,
  1046. _DomainGreater(0.0))
  1047. log10 = _MaskedUnaryOperation(umath.log10, 1.0,
  1048. _DomainGreater(0.0))
  1049. tan = _MaskedUnaryOperation(umath.tan, 0.0,
  1050. _DomainTan(1e-35))
  1051. arcsin = _MaskedUnaryOperation(umath.arcsin, 0.0,
  1052. _DomainCheckInterval(-1.0, 1.0))
  1053. arccos = _MaskedUnaryOperation(umath.arccos, 0.0,
  1054. _DomainCheckInterval(-1.0, 1.0))
  1055. arccosh = _MaskedUnaryOperation(umath.arccosh, 1.0,
  1056. _DomainGreaterEqual(1.0))
  1057. arctanh = _MaskedUnaryOperation(umath.arctanh, 0.0,
  1058. _DomainCheckInterval(-1.0 + 1e-15, 1.0 - 1e-15))
  1059. # Binary ufuncs
  1060. add = _MaskedBinaryOperation(umath.add)
  1061. subtract = _MaskedBinaryOperation(umath.subtract)
  1062. multiply = _MaskedBinaryOperation(umath.multiply, 1, 1)
  1063. arctan2 = _MaskedBinaryOperation(umath.arctan2, 0.0, 1.0)
  1064. equal = _MaskedBinaryOperation(umath.equal)
  1065. equal.reduce = None
  1066. not_equal = _MaskedBinaryOperation(umath.not_equal)
  1067. not_equal.reduce = None
  1068. less_equal = _MaskedBinaryOperation(umath.less_equal)
  1069. less_equal.reduce = None
  1070. greater_equal = _MaskedBinaryOperation(umath.greater_equal)
  1071. greater_equal.reduce = None
  1072. less = _MaskedBinaryOperation(umath.less)
  1073. less.reduce = None
  1074. greater = _MaskedBinaryOperation(umath.greater)
  1075. greater.reduce = None
  1076. logical_and = _MaskedBinaryOperation(umath.logical_and)
  1077. alltrue = _MaskedBinaryOperation(umath.logical_and, 1, 1).reduce
  1078. logical_or = _MaskedBinaryOperation(umath.logical_or)
  1079. sometrue = logical_or.reduce
  1080. logical_xor = _MaskedBinaryOperation(umath.logical_xor)
  1081. bitwise_and = _MaskedBinaryOperation(umath.bitwise_and)
  1082. bitwise_or = _MaskedBinaryOperation(umath.bitwise_or)
  1083. bitwise_xor = _MaskedBinaryOperation(umath.bitwise_xor)
  1084. hypot = _MaskedBinaryOperation(umath.hypot)
  1085. # Domained binary ufuncs
  1086. divide = _DomainedBinaryOperation(umath.divide, _DomainSafeDivide(), 0, 1)
  1087. true_divide = _DomainedBinaryOperation(umath.true_divide,
  1088. _DomainSafeDivide(), 0, 1)
  1089. floor_divide = _DomainedBinaryOperation(umath.floor_divide,
  1090. _DomainSafeDivide(), 0, 1)
  1091. remainder = _DomainedBinaryOperation(umath.remainder,
  1092. _DomainSafeDivide(), 0, 1)
  1093. fmod = _DomainedBinaryOperation(umath.fmod, _DomainSafeDivide(), 0, 1)
  1094. mod = _DomainedBinaryOperation(umath.mod, _DomainSafeDivide(), 0, 1)
  1095. ###############################################################################
  1096. # Mask creation functions #
  1097. ###############################################################################
  1098. def _replace_dtype_fields_recursive(dtype, primitive_dtype):
  1099. "Private function allowing recursion in _replace_dtype_fields."
  1100. _recurse = _replace_dtype_fields_recursive
  1101. # Do we have some name fields ?
  1102. if dtype.names is not None:
  1103. descr = []
  1104. for name in dtype.names:
  1105. field = dtype.fields[name]
  1106. if len(field) == 3:
  1107. # Prepend the title to the name
  1108. name = (field[-1], name)
  1109. descr.append((name, _recurse(field[0], primitive_dtype)))
  1110. new_dtype = np.dtype(descr)
  1111. # Is this some kind of composite a la (float,2)
  1112. elif dtype.subdtype:
  1113. descr = list(dtype.subdtype)
  1114. descr[0] = _recurse(dtype.subdtype[0], primitive_dtype)
  1115. new_dtype = np.dtype(tuple(descr))
  1116. # this is a primitive type, so do a direct replacement
  1117. else:
  1118. new_dtype = primitive_dtype
  1119. # preserve identity of dtypes
  1120. if new_dtype == dtype:
  1121. new_dtype = dtype
  1122. return new_dtype
  1123. def _replace_dtype_fields(dtype, primitive_dtype):
  1124. """
  1125. Construct a dtype description list from a given dtype.
  1126. Returns a new dtype object, with all fields and subtypes in the given type
  1127. recursively replaced with `primitive_dtype`.
  1128. Arguments are coerced to dtypes first.
  1129. """
  1130. dtype = np.dtype(dtype)
  1131. primitive_dtype = np.dtype(primitive_dtype)
  1132. return _replace_dtype_fields_recursive(dtype, primitive_dtype)
  1133. def make_mask_descr(ndtype):
  1134. """
  1135. Construct a dtype description list from a given dtype.
  1136. Returns a new dtype object, with the type of all fields in `ndtype` to a
  1137. boolean type. Field names are not altered.
  1138. Parameters
  1139. ----------
  1140. ndtype : dtype
  1141. The dtype to convert.
  1142. Returns
  1143. -------
  1144. result : dtype
  1145. A dtype that looks like `ndtype`, the type of all fields is boolean.
  1146. Examples
  1147. --------
  1148. >>> import numpy as np
  1149. >>> import numpy.ma as ma
  1150. >>> dtype = np.dtype({'names':['foo', 'bar'],
  1151. ... 'formats':[np.float32, np.int64]})
  1152. >>> dtype
  1153. dtype([('foo', '<f4'), ('bar', '<i8')])
  1154. >>> ma.make_mask_descr(dtype)
  1155. dtype([('foo', '|b1'), ('bar', '|b1')])
  1156. >>> ma.make_mask_descr(np.float32)
  1157. dtype('bool')
  1158. """
  1159. return _replace_dtype_fields(ndtype, MaskType)
  1160. def getmask(a):
  1161. """
  1162. Return the mask of a masked array, or nomask.
  1163. Return the mask of `a` as an ndarray if `a` is a `MaskedArray` and the
  1164. mask is not `nomask`, else return `nomask`. To guarantee a full array
  1165. of booleans of the same shape as a, use `getmaskarray`.
  1166. Parameters
  1167. ----------
  1168. a : array_like
  1169. Input `MaskedArray` for which the mask is required.
  1170. See Also
  1171. --------
  1172. getdata : Return the data of a masked array as an ndarray.
  1173. getmaskarray : Return the mask of a masked array, or full array of False.
  1174. Examples
  1175. --------
  1176. >>> import numpy as np
  1177. >>> import numpy.ma as ma
  1178. >>> a = ma.masked_equal([[1,2],[3,4]], 2)
  1179. >>> a
  1180. masked_array(
  1181. data=[[1, --],
  1182. [3, 4]],
  1183. mask=[[False, True],
  1184. [False, False]],
  1185. fill_value=2)
  1186. >>> ma.getmask(a)
  1187. array([[False, True],
  1188. [False, False]])
  1189. Equivalently use the `MaskedArray` `mask` attribute.
  1190. >>> a.mask
  1191. array([[False, True],
  1192. [False, False]])
  1193. Result when mask == `nomask`
  1194. >>> b = ma.masked_array([[1,2],[3,4]])
  1195. >>> b
  1196. masked_array(
  1197. data=[[1, 2],
  1198. [3, 4]],
  1199. mask=False,
  1200. fill_value=999999)
  1201. >>> ma.nomask
  1202. False
  1203. >>> ma.getmask(b) == ma.nomask
  1204. True
  1205. >>> b.mask == ma.nomask
  1206. True
  1207. """
  1208. return getattr(a, '_mask', nomask)
  1209. get_mask = getmask
  1210. def getmaskarray(arr):
  1211. """
  1212. Return the mask of a masked array, or full boolean array of False.
  1213. Return the mask of `arr` as an ndarray if `arr` is a `MaskedArray` and
  1214. the mask is not `nomask`, else return a full boolean array of False of
  1215. the same shape as `arr`.
  1216. Parameters
  1217. ----------
  1218. arr : array_like
  1219. Input `MaskedArray` for which the mask is required.
  1220. See Also
  1221. --------
  1222. getmask : Return the mask of a masked array, or nomask.
  1223. getdata : Return the data of a masked array as an ndarray.
  1224. Examples
  1225. --------
  1226. >>> import numpy as np
  1227. >>> import numpy.ma as ma
  1228. >>> a = ma.masked_equal([[1,2],[3,4]], 2)
  1229. >>> a
  1230. masked_array(
  1231. data=[[1, --],
  1232. [3, 4]],
  1233. mask=[[False, True],
  1234. [False, False]],
  1235. fill_value=2)
  1236. >>> ma.getmaskarray(a)
  1237. array([[False, True],
  1238. [False, False]])
  1239. Result when mask == ``nomask``
  1240. >>> b = ma.masked_array([[1,2],[3,4]])
  1241. >>> b
  1242. masked_array(
  1243. data=[[1, 2],
  1244. [3, 4]],
  1245. mask=False,
  1246. fill_value=999999)
  1247. >>> ma.getmaskarray(b)
  1248. array([[False, False],
  1249. [False, False]])
  1250. """
  1251. mask = getmask(arr)
  1252. if mask is nomask:
  1253. mask = make_mask_none(np.shape(arr), getattr(arr, 'dtype', None))
  1254. return mask
  1255. def is_mask(m):
  1256. """
  1257. Return True if m is a valid, standard mask.
  1258. This function does not check the contents of the input, only that the
  1259. type is MaskType. In particular, this function returns False if the
  1260. mask has a flexible dtype.
  1261. Parameters
  1262. ----------
  1263. m : array_like
  1264. Array to test.
  1265. Returns
  1266. -------
  1267. result : bool
  1268. True if `m.dtype.type` is MaskType, False otherwise.
  1269. See Also
  1270. --------
  1271. ma.isMaskedArray : Test whether input is an instance of MaskedArray.
  1272. Examples
  1273. --------
  1274. >>> import numpy as np
  1275. >>> import numpy.ma as ma
  1276. >>> m = ma.masked_equal([0, 1, 0, 2, 3], 0)
  1277. >>> m
  1278. masked_array(data=[--, 1, --, 2, 3],
  1279. mask=[ True, False, True, False, False],
  1280. fill_value=0)
  1281. >>> ma.is_mask(m)
  1282. False
  1283. >>> ma.is_mask(m.mask)
  1284. True
  1285. Input must be an ndarray (or have similar attributes)
  1286. for it to be considered a valid mask.
  1287. >>> m = [False, True, False]
  1288. >>> ma.is_mask(m)
  1289. False
  1290. >>> m = np.array([False, True, False])
  1291. >>> m
  1292. array([False, True, False])
  1293. >>> ma.is_mask(m)
  1294. True
  1295. Arrays with complex dtypes don't return True.
  1296. >>> dtype = np.dtype({'names':['monty', 'pithon'],
  1297. ... 'formats':[bool, bool]})
  1298. >>> dtype
  1299. dtype([('monty', '|b1'), ('pithon', '|b1')])
  1300. >>> m = np.array([(True, False), (False, True), (True, False)],
  1301. ... dtype=dtype)
  1302. >>> m
  1303. array([( True, False), (False, True), ( True, False)],
  1304. dtype=[('monty', '?'), ('pithon', '?')])
  1305. >>> ma.is_mask(m)
  1306. False
  1307. """
  1308. try:
  1309. return m.dtype.type is MaskType
  1310. except AttributeError:
  1311. return False
  1312. def _shrink_mask(m):
  1313. """
  1314. Shrink a mask to nomask if possible
  1315. """
  1316. if m.dtype.names is None and not m.any():
  1317. return nomask
  1318. else:
  1319. return m
  1320. def make_mask(m, copy=False, shrink=True, dtype=MaskType):
  1321. """
  1322. Create a boolean mask from an array.
  1323. Return `m` as a boolean mask, creating a copy if necessary or requested.
  1324. The function can accept any sequence that is convertible to integers,
  1325. or ``nomask``. Does not require that contents must be 0s and 1s, values
  1326. of 0 are interpreted as False, everything else as True.
  1327. Parameters
  1328. ----------
  1329. m : array_like
  1330. Potential mask.
  1331. copy : bool, optional
  1332. Whether to return a copy of `m` (True) or `m` itself (False).
  1333. shrink : bool, optional
  1334. Whether to shrink `m` to ``nomask`` if all its values are False.
  1335. dtype : dtype, optional
  1336. Data-type of the output mask. By default, the output mask has a
  1337. dtype of MaskType (bool). If the dtype is flexible, each field has
  1338. a boolean dtype. This is ignored when `m` is ``nomask``, in which
  1339. case ``nomask`` is always returned.
  1340. Returns
  1341. -------
  1342. result : ndarray
  1343. A boolean mask derived from `m`.
  1344. Examples
  1345. --------
  1346. >>> import numpy as np
  1347. >>> import numpy.ma as ma
  1348. >>> m = [True, False, True, True]
  1349. >>> ma.make_mask(m)
  1350. array([ True, False, True, True])
  1351. >>> m = [1, 0, 1, 1]
  1352. >>> ma.make_mask(m)
  1353. array([ True, False, True, True])
  1354. >>> m = [1, 0, 2, -3]
  1355. >>> ma.make_mask(m)
  1356. array([ True, False, True, True])
  1357. Effect of the `shrink` parameter.
  1358. >>> m = np.zeros(4)
  1359. >>> m
  1360. array([0., 0., 0., 0.])
  1361. >>> ma.make_mask(m)
  1362. False
  1363. >>> ma.make_mask(m, shrink=False)
  1364. array([False, False, False, False])
  1365. Using a flexible `dtype`.
  1366. >>> m = [1, 0, 1, 1]
  1367. >>> n = [0, 1, 0, 0]
  1368. >>> arr = []
  1369. >>> for man, mouse in zip(m, n):
  1370. ... arr.append((man, mouse))
  1371. >>> arr
  1372. [(1, 0), (0, 1), (1, 0), (1, 0)]
  1373. >>> dtype = np.dtype({'names':['man', 'mouse'],
  1374. ... 'formats':[np.int64, np.int64]})
  1375. >>> arr = np.array(arr, dtype=dtype)
  1376. >>> arr
  1377. array([(1, 0), (0, 1), (1, 0), (1, 0)],
  1378. dtype=[('man', '<i8'), ('mouse', '<i8')])
  1379. >>> ma.make_mask(arr, dtype=dtype)
  1380. array([(True, False), (False, True), (True, False), (True, False)],
  1381. dtype=[('man', '|b1'), ('mouse', '|b1')])
  1382. """
  1383. if m is nomask:
  1384. return nomask
  1385. # Make sure the input dtype is valid.
  1386. dtype = make_mask_descr(dtype)
  1387. # legacy boolean special case: "existence of fields implies true"
  1388. if isinstance(m, ndarray) and m.dtype.fields and dtype == np.bool:
  1389. return np.ones(m.shape, dtype=dtype)
  1390. # Fill the mask in case there are missing data; turn it into an ndarray.
  1391. copy = None if not copy else True
  1392. result = np.array(filled(m, True), copy=copy, dtype=dtype, subok=True)
  1393. # Bas les masques !
  1394. if shrink:
  1395. result = _shrink_mask(result)
  1396. return result
  1397. def make_mask_none(newshape, dtype=None):
  1398. """
  1399. Return a boolean mask of the given shape, filled with False.
  1400. This function returns a boolean ndarray with all entries False, that can
  1401. be used in common mask manipulations. If a complex dtype is specified, the
  1402. type of each field is converted to a boolean type.
  1403. Parameters
  1404. ----------
  1405. newshape : tuple
  1406. A tuple indicating the shape of the mask.
  1407. dtype : {None, dtype}, optional
  1408. If None, use a MaskType instance. Otherwise, use a new datatype with
  1409. the same fields as `dtype`, converted to boolean types.
  1410. Returns
  1411. -------
  1412. result : ndarray
  1413. An ndarray of appropriate shape and dtype, filled with False.
  1414. See Also
  1415. --------
  1416. make_mask : Create a boolean mask from an array.
  1417. make_mask_descr : Construct a dtype description list from a given dtype.
  1418. Examples
  1419. --------
  1420. >>> import numpy as np
  1421. >>> import numpy.ma as ma
  1422. >>> ma.make_mask_none((3,))
  1423. array([False, False, False])
  1424. Defining a more complex dtype.
  1425. >>> dtype = np.dtype({'names':['foo', 'bar'],
  1426. ... 'formats':[np.float32, np.int64]})
  1427. >>> dtype
  1428. dtype([('foo', '<f4'), ('bar', '<i8')])
  1429. >>> ma.make_mask_none((3,), dtype=dtype)
  1430. array([(False, False), (False, False), (False, False)],
  1431. dtype=[('foo', '|b1'), ('bar', '|b1')])
  1432. """
  1433. if dtype is None:
  1434. result = np.zeros(newshape, dtype=MaskType)
  1435. else:
  1436. result = np.zeros(newshape, dtype=make_mask_descr(dtype))
  1437. return result
  1438. def _recursive_mask_or(m1, m2, newmask):
  1439. names = m1.dtype.names
  1440. for name in names:
  1441. current1 = m1[name]
  1442. if current1.dtype.names is not None:
  1443. _recursive_mask_or(current1, m2[name], newmask[name])
  1444. else:
  1445. umath.logical_or(current1, m2[name], newmask[name])
  1446. def mask_or(m1, m2, copy=False, shrink=True):
  1447. """
  1448. Combine two masks with the ``logical_or`` operator.
  1449. The result may be a view on `m1` or `m2` if the other is `nomask`
  1450. (i.e. False).
  1451. Parameters
  1452. ----------
  1453. m1, m2 : array_like
  1454. Input masks.
  1455. copy : bool, optional
  1456. If copy is False and one of the inputs is `nomask`, return a view
  1457. of the other input mask. Defaults to False.
  1458. shrink : bool, optional
  1459. Whether to shrink the output to `nomask` if all its values are
  1460. False. Defaults to True.
  1461. Returns
  1462. -------
  1463. mask : output mask
  1464. The result masks values that are masked in either `m1` or `m2`.
  1465. Raises
  1466. ------
  1467. ValueError
  1468. If `m1` and `m2` have different flexible dtypes.
  1469. Examples
  1470. --------
  1471. >>> import numpy as np
  1472. >>> m1 = np.ma.make_mask([0, 1, 1, 0])
  1473. >>> m2 = np.ma.make_mask([1, 0, 0, 0])
  1474. >>> np.ma.mask_or(m1, m2)
  1475. array([ True, True, True, False])
  1476. """
  1477. if (m1 is nomask) or (m1 is False):
  1478. dtype = getattr(m2, 'dtype', MaskType)
  1479. return make_mask(m2, copy=copy, shrink=shrink, dtype=dtype)
  1480. if (m2 is nomask) or (m2 is False):
  1481. dtype = getattr(m1, 'dtype', MaskType)
  1482. return make_mask(m1, copy=copy, shrink=shrink, dtype=dtype)
  1483. if m1 is m2 and is_mask(m1):
  1484. return _shrink_mask(m1) if shrink else m1
  1485. (dtype1, dtype2) = (getattr(m1, 'dtype', None), getattr(m2, 'dtype', None))
  1486. if dtype1 != dtype2:
  1487. raise ValueError("Incompatible dtypes '%s'<>'%s'" % (dtype1, dtype2))
  1488. if dtype1.names is not None:
  1489. # Allocate an output mask array with the properly broadcast shape.
  1490. newmask = np.empty(np.broadcast(m1, m2).shape, dtype1)
  1491. _recursive_mask_or(m1, m2, newmask)
  1492. return newmask
  1493. return make_mask(umath.logical_or(m1, m2), copy=copy, shrink=shrink)
  1494. def flatten_mask(mask):
  1495. """
  1496. Returns a completely flattened version of the mask, where nested fields
  1497. are collapsed.
  1498. Parameters
  1499. ----------
  1500. mask : array_like
  1501. Input array, which will be interpreted as booleans.
  1502. Returns
  1503. -------
  1504. flattened_mask : ndarray of bools
  1505. The flattened input.
  1506. Examples
  1507. --------
  1508. >>> import numpy as np
  1509. >>> mask = np.array([0, 0, 1])
  1510. >>> np.ma.flatten_mask(mask)
  1511. array([False, False, True])
  1512. >>> mask = np.array([(0, 0), (0, 1)], dtype=[('a', bool), ('b', bool)])
  1513. >>> np.ma.flatten_mask(mask)
  1514. array([False, False, False, True])
  1515. >>> mdtype = [('a', bool), ('b', [('ba', bool), ('bb', bool)])]
  1516. >>> mask = np.array([(0, (0, 0)), (0, (0, 1))], dtype=mdtype)
  1517. >>> np.ma.flatten_mask(mask)
  1518. array([False, False, False, False, False, True])
  1519. """
  1520. def _flatmask(mask):
  1521. "Flatten the mask and returns a (maybe nested) sequence of booleans."
  1522. mnames = mask.dtype.names
  1523. if mnames is not None:
  1524. return [flatten_mask(mask[name]) for name in mnames]
  1525. else:
  1526. return mask
  1527. def _flatsequence(sequence):
  1528. "Generates a flattened version of the sequence."
  1529. try:
  1530. for element in sequence:
  1531. if hasattr(element, '__iter__'):
  1532. yield from _flatsequence(element)
  1533. else:
  1534. yield element
  1535. except TypeError:
  1536. yield sequence
  1537. mask = np.asarray(mask)
  1538. flattened = _flatsequence(_flatmask(mask))
  1539. return np.array(list(flattened), dtype=bool)
  1540. def _check_mask_axis(mask, axis, keepdims=np._NoValue):
  1541. "Check whether there are masked values along the given axis"
  1542. kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
  1543. if mask is not nomask:
  1544. return mask.all(axis=axis, **kwargs)
  1545. return nomask
  1546. ###############################################################################
  1547. # Masking functions #
  1548. ###############################################################################
  1549. def masked_where(condition, a, copy=True):
  1550. """
  1551. Mask an array where a condition is met.
  1552. Return `a` as an array masked where `condition` is True.
  1553. Any masked values of `a` or `condition` are also masked in the output.
  1554. Parameters
  1555. ----------
  1556. condition : array_like
  1557. Masking condition. When `condition` tests floating point values for
  1558. equality, consider using ``masked_values`` instead.
  1559. a : array_like
  1560. Array to mask.
  1561. copy : bool
  1562. If True (default) make a copy of `a` in the result. If False modify
  1563. `a` in place and return a view.
  1564. Returns
  1565. -------
  1566. result : MaskedArray
  1567. The result of masking `a` where `condition` is True.
  1568. See Also
  1569. --------
  1570. masked_values : Mask using floating point equality.
  1571. masked_equal : Mask where equal to a given value.
  1572. masked_not_equal : Mask where *not* equal to a given value.
  1573. masked_less_equal : Mask where less than or equal to a given value.
  1574. masked_greater_equal : Mask where greater than or equal to a given value.
  1575. masked_less : Mask where less than a given value.
  1576. masked_greater : Mask where greater than a given value.
  1577. masked_inside : Mask inside a given interval.
  1578. masked_outside : Mask outside a given interval.
  1579. masked_invalid : Mask invalid values (NaNs or infs).
  1580. Examples
  1581. --------
  1582. >>> import numpy as np
  1583. >>> import numpy.ma as ma
  1584. >>> a = np.arange(4)
  1585. >>> a
  1586. array([0, 1, 2, 3])
  1587. >>> ma.masked_where(a <= 2, a)
  1588. masked_array(data=[--, --, --, 3],
  1589. mask=[ True, True, True, False],
  1590. fill_value=999999)
  1591. Mask array `b` conditional on `a`.
  1592. >>> b = ['a', 'b', 'c', 'd']
  1593. >>> ma.masked_where(a == 2, b)
  1594. masked_array(data=['a', 'b', --, 'd'],
  1595. mask=[False, False, True, False],
  1596. fill_value='N/A',
  1597. dtype='<U1')
  1598. Effect of the `copy` argument.
  1599. >>> c = ma.masked_where(a <= 2, a)
  1600. >>> c
  1601. masked_array(data=[--, --, --, 3],
  1602. mask=[ True, True, True, False],
  1603. fill_value=999999)
  1604. >>> c[0] = 99
  1605. >>> c
  1606. masked_array(data=[99, --, --, 3],
  1607. mask=[False, True, True, False],
  1608. fill_value=999999)
  1609. >>> a
  1610. array([0, 1, 2, 3])
  1611. >>> c = ma.masked_where(a <= 2, a, copy=False)
  1612. >>> c[0] = 99
  1613. >>> c
  1614. masked_array(data=[99, --, --, 3],
  1615. mask=[False, True, True, False],
  1616. fill_value=999999)
  1617. >>> a
  1618. array([99, 1, 2, 3])
  1619. When `condition` or `a` contain masked values.
  1620. >>> a = np.arange(4)
  1621. >>> a = ma.masked_where(a == 2, a)
  1622. >>> a
  1623. masked_array(data=[0, 1, --, 3],
  1624. mask=[False, False, True, False],
  1625. fill_value=999999)
  1626. >>> b = np.arange(4)
  1627. >>> b = ma.masked_where(b == 0, b)
  1628. >>> b
  1629. masked_array(data=[--, 1, 2, 3],
  1630. mask=[ True, False, False, False],
  1631. fill_value=999999)
  1632. >>> ma.masked_where(a == 3, b)
  1633. masked_array(data=[--, 1, --, --],
  1634. mask=[ True, False, True, True],
  1635. fill_value=999999)
  1636. """
  1637. # Make sure that condition is a valid standard-type mask.
  1638. cond = make_mask(condition, shrink=False)
  1639. a = np.array(a, copy=copy, subok=True)
  1640. (cshape, ashape) = (cond.shape, a.shape)
  1641. if cshape and cshape != ashape:
  1642. raise IndexError("Inconsistent shape between the condition and the input"
  1643. " (got %s and %s)" % (cshape, ashape))
  1644. if hasattr(a, '_mask'):
  1645. cond = mask_or(cond, a._mask)
  1646. cls = type(a)
  1647. else:
  1648. cls = MaskedArray
  1649. result = a.view(cls)
  1650. # Assign to *.mask so that structured masks are handled correctly.
  1651. result.mask = _shrink_mask(cond)
  1652. # There is no view of a boolean so when 'a' is a MaskedArray with nomask
  1653. # the update to the result's mask has no effect.
  1654. if not copy and hasattr(a, '_mask') and getmask(a) is nomask:
  1655. a._mask = result._mask.view()
  1656. return result
  1657. def masked_greater(x, value, copy=True):
  1658. """
  1659. Mask an array where greater than a given value.
  1660. This function is a shortcut to ``masked_where``, with
  1661. `condition` = (x > value).
  1662. See Also
  1663. --------
  1664. masked_where : Mask where a condition is met.
  1665. Examples
  1666. --------
  1667. >>> import numpy as np
  1668. >>> import numpy.ma as ma
  1669. >>> a = np.arange(4)
  1670. >>> a
  1671. array([0, 1, 2, 3])
  1672. >>> ma.masked_greater(a, 2)
  1673. masked_array(data=[0, 1, 2, --],
  1674. mask=[False, False, False, True],
  1675. fill_value=999999)
  1676. """
  1677. return masked_where(greater(x, value), x, copy=copy)
  1678. def masked_greater_equal(x, value, copy=True):
  1679. """
  1680. Mask an array where greater than or equal to a given value.
  1681. This function is a shortcut to ``masked_where``, with
  1682. `condition` = (x >= value).
  1683. See Also
  1684. --------
  1685. masked_where : Mask where a condition is met.
  1686. Examples
  1687. --------
  1688. >>> import numpy as np
  1689. >>> import numpy.ma as ma
  1690. >>> a = np.arange(4)
  1691. >>> a
  1692. array([0, 1, 2, 3])
  1693. >>> ma.masked_greater_equal(a, 2)
  1694. masked_array(data=[0, 1, --, --],
  1695. mask=[False, False, True, True],
  1696. fill_value=999999)
  1697. """
  1698. return masked_where(greater_equal(x, value), x, copy=copy)
  1699. def masked_less(x, value, copy=True):
  1700. """
  1701. Mask an array where less than a given value.
  1702. This function is a shortcut to ``masked_where``, with
  1703. `condition` = (x < value).
  1704. See Also
  1705. --------
  1706. masked_where : Mask where a condition is met.
  1707. Examples
  1708. --------
  1709. >>> import numpy as np
  1710. >>> import numpy.ma as ma
  1711. >>> a = np.arange(4)
  1712. >>> a
  1713. array([0, 1, 2, 3])
  1714. >>> ma.masked_less(a, 2)
  1715. masked_array(data=[--, --, 2, 3],
  1716. mask=[ True, True, False, False],
  1717. fill_value=999999)
  1718. """
  1719. return masked_where(less(x, value), x, copy=copy)
  1720. def masked_less_equal(x, value, copy=True):
  1721. """
  1722. Mask an array where less than or equal to a given value.
  1723. This function is a shortcut to ``masked_where``, with
  1724. `condition` = (x <= value).
  1725. See Also
  1726. --------
  1727. masked_where : Mask where a condition is met.
  1728. Examples
  1729. --------
  1730. >>> import numpy as np
  1731. >>> import numpy.ma as ma
  1732. >>> a = np.arange(4)
  1733. >>> a
  1734. array([0, 1, 2, 3])
  1735. >>> ma.masked_less_equal(a, 2)
  1736. masked_array(data=[--, --, --, 3],
  1737. mask=[ True, True, True, False],
  1738. fill_value=999999)
  1739. """
  1740. return masked_where(less_equal(x, value), x, copy=copy)
  1741. def masked_not_equal(x, value, copy=True):
  1742. """
  1743. Mask an array where *not* equal to a given value.
  1744. This function is a shortcut to ``masked_where``, with
  1745. `condition` = (x != value).
  1746. See Also
  1747. --------
  1748. masked_where : Mask where a condition is met.
  1749. Examples
  1750. --------
  1751. >>> import numpy as np
  1752. >>> import numpy.ma as ma
  1753. >>> a = np.arange(4)
  1754. >>> a
  1755. array([0, 1, 2, 3])
  1756. >>> ma.masked_not_equal(a, 2)
  1757. masked_array(data=[--, --, 2, --],
  1758. mask=[ True, True, False, True],
  1759. fill_value=999999)
  1760. """
  1761. return masked_where(not_equal(x, value), x, copy=copy)
  1762. def masked_equal(x, value, copy=True):
  1763. """
  1764. Mask an array where equal to a given value.
  1765. Return a MaskedArray, masked where the data in array `x` are
  1766. equal to `value`. The fill_value of the returned MaskedArray
  1767. is set to `value`.
  1768. For floating point arrays, consider using ``masked_values(x, value)``.
  1769. See Also
  1770. --------
  1771. masked_where : Mask where a condition is met.
  1772. masked_values : Mask using floating point equality.
  1773. Examples
  1774. --------
  1775. >>> import numpy as np
  1776. >>> import numpy.ma as ma
  1777. >>> a = np.arange(4)
  1778. >>> a
  1779. array([0, 1, 2, 3])
  1780. >>> ma.masked_equal(a, 2)
  1781. masked_array(data=[0, 1, --, 3],
  1782. mask=[False, False, True, False],
  1783. fill_value=2)
  1784. """
  1785. output = masked_where(equal(x, value), x, copy=copy)
  1786. output.fill_value = value
  1787. return output
  1788. def masked_inside(x, v1, v2, copy=True):
  1789. """
  1790. Mask an array inside a given interval.
  1791. Shortcut to ``masked_where``, where `condition` is True for `x` inside
  1792. the interval [v1,v2] (v1 <= x <= v2). The boundaries `v1` and `v2`
  1793. can be given in either order.
  1794. See Also
  1795. --------
  1796. masked_where : Mask where a condition is met.
  1797. Notes
  1798. -----
  1799. The array `x` is prefilled with its filling value.
  1800. Examples
  1801. --------
  1802. >>> import numpy as np
  1803. >>> import numpy.ma as ma
  1804. >>> x = [0.31, 1.2, 0.01, 0.2, -0.4, -1.1]
  1805. >>> ma.masked_inside(x, -0.3, 0.3)
  1806. masked_array(data=[0.31, 1.2, --, --, -0.4, -1.1],
  1807. mask=[False, False, True, True, False, False],
  1808. fill_value=1e+20)
  1809. The order of `v1` and `v2` doesn't matter.
  1810. >>> ma.masked_inside(x, 0.3, -0.3)
  1811. masked_array(data=[0.31, 1.2, --, --, -0.4, -1.1],
  1812. mask=[False, False, True, True, False, False],
  1813. fill_value=1e+20)
  1814. """
  1815. if v2 < v1:
  1816. (v1, v2) = (v2, v1)
  1817. xf = filled(x)
  1818. condition = (xf >= v1) & (xf <= v2)
  1819. return masked_where(condition, x, copy=copy)
  1820. def masked_outside(x, v1, v2, copy=True):
  1821. """
  1822. Mask an array outside a given interval.
  1823. Shortcut to ``masked_where``, where `condition` is True for `x` outside
  1824. the interval [v1,v2] (x < v1)|(x > v2).
  1825. The boundaries `v1` and `v2` can be given in either order.
  1826. See Also
  1827. --------
  1828. masked_where : Mask where a condition is met.
  1829. Notes
  1830. -----
  1831. The array `x` is prefilled with its filling value.
  1832. Examples
  1833. --------
  1834. >>> import numpy as np
  1835. >>> import numpy.ma as ma
  1836. >>> x = [0.31, 1.2, 0.01, 0.2, -0.4, -1.1]
  1837. >>> ma.masked_outside(x, -0.3, 0.3)
  1838. masked_array(data=[--, --, 0.01, 0.2, --, --],
  1839. mask=[ True, True, False, False, True, True],
  1840. fill_value=1e+20)
  1841. The order of `v1` and `v2` doesn't matter.
  1842. >>> ma.masked_outside(x, 0.3, -0.3)
  1843. masked_array(data=[--, --, 0.01, 0.2, --, --],
  1844. mask=[ True, True, False, False, True, True],
  1845. fill_value=1e+20)
  1846. """
  1847. if v2 < v1:
  1848. (v1, v2) = (v2, v1)
  1849. xf = filled(x)
  1850. condition = (xf < v1) | (xf > v2)
  1851. return masked_where(condition, x, copy=copy)
  1852. def masked_object(x, value, copy=True, shrink=True):
  1853. """
  1854. Mask the array `x` where the data are exactly equal to value.
  1855. This function is similar to `masked_values`, but only suitable
  1856. for object arrays: for floating point, use `masked_values` instead.
  1857. Parameters
  1858. ----------
  1859. x : array_like
  1860. Array to mask
  1861. value : object
  1862. Comparison value
  1863. copy : {True, False}, optional
  1864. Whether to return a copy of `x`.
  1865. shrink : {True, False}, optional
  1866. Whether to collapse a mask full of False to nomask
  1867. Returns
  1868. -------
  1869. result : MaskedArray
  1870. The result of masking `x` where equal to `value`.
  1871. See Also
  1872. --------
  1873. masked_where : Mask where a condition is met.
  1874. masked_equal : Mask where equal to a given value (integers).
  1875. masked_values : Mask using floating point equality.
  1876. Examples
  1877. --------
  1878. >>> import numpy as np
  1879. >>> import numpy.ma as ma
  1880. >>> food = np.array(['green_eggs', 'ham'], dtype=object)
  1881. >>> # don't eat spoiled food
  1882. >>> eat = ma.masked_object(food, 'green_eggs')
  1883. >>> eat
  1884. masked_array(data=[--, 'ham'],
  1885. mask=[ True, False],
  1886. fill_value='green_eggs',
  1887. dtype=object)
  1888. >>> # plain ol` ham is boring
  1889. >>> fresh_food = np.array(['cheese', 'ham', 'pineapple'], dtype=object)
  1890. >>> eat = ma.masked_object(fresh_food, 'green_eggs')
  1891. >>> eat
  1892. masked_array(data=['cheese', 'ham', 'pineapple'],
  1893. mask=False,
  1894. fill_value='green_eggs',
  1895. dtype=object)
  1896. Note that `mask` is set to ``nomask`` if possible.
  1897. >>> eat
  1898. masked_array(data=['cheese', 'ham', 'pineapple'],
  1899. mask=False,
  1900. fill_value='green_eggs',
  1901. dtype=object)
  1902. """
  1903. if isMaskedArray(x):
  1904. condition = umath.equal(x._data, value)
  1905. mask = x._mask
  1906. else:
  1907. condition = umath.equal(np.asarray(x), value)
  1908. mask = nomask
  1909. mask = mask_or(mask, make_mask(condition, shrink=shrink))
  1910. return masked_array(x, mask=mask, copy=copy, fill_value=value)
  1911. def masked_values(x, value, rtol=1e-5, atol=1e-8, copy=True, shrink=True):
  1912. """
  1913. Mask using floating point equality.
  1914. Return a MaskedArray, masked where the data in array `x` are approximately
  1915. equal to `value`, determined using `isclose`. The default tolerances for
  1916. `masked_values` are the same as those for `isclose`.
  1917. For integer types, exact equality is used, in the same way as
  1918. `masked_equal`.
  1919. The fill_value is set to `value` and the mask is set to ``nomask`` if
  1920. possible.
  1921. Parameters
  1922. ----------
  1923. x : array_like
  1924. Array to mask.
  1925. value : float
  1926. Masking value.
  1927. rtol, atol : float, optional
  1928. Tolerance parameters passed on to `isclose`
  1929. copy : bool, optional
  1930. Whether to return a copy of `x`.
  1931. shrink : bool, optional
  1932. Whether to collapse a mask full of False to ``nomask``.
  1933. Returns
  1934. -------
  1935. result : MaskedArray
  1936. The result of masking `x` where approximately equal to `value`.
  1937. See Also
  1938. --------
  1939. masked_where : Mask where a condition is met.
  1940. masked_equal : Mask where equal to a given value (integers).
  1941. Examples
  1942. --------
  1943. >>> import numpy as np
  1944. >>> import numpy.ma as ma
  1945. >>> x = np.array([1, 1.1, 2, 1.1, 3])
  1946. >>> ma.masked_values(x, 1.1)
  1947. masked_array(data=[1.0, --, 2.0, --, 3.0],
  1948. mask=[False, True, False, True, False],
  1949. fill_value=1.1)
  1950. Note that `mask` is set to ``nomask`` if possible.
  1951. >>> ma.masked_values(x, 2.1)
  1952. masked_array(data=[1. , 1.1, 2. , 1.1, 3. ],
  1953. mask=False,
  1954. fill_value=2.1)
  1955. Unlike `masked_equal`, `masked_values` can perform approximate equalities.
  1956. >>> ma.masked_values(x, 2.1, atol=1e-1)
  1957. masked_array(data=[1.0, 1.1, --, 1.1, 3.0],
  1958. mask=[False, False, True, False, False],
  1959. fill_value=2.1)
  1960. """
  1961. xnew = filled(x, value)
  1962. if np.issubdtype(xnew.dtype, np.floating):
  1963. mask = np.isclose(xnew, value, atol=atol, rtol=rtol)
  1964. else:
  1965. mask = umath.equal(xnew, value)
  1966. ret = masked_array(xnew, mask=mask, copy=copy, fill_value=value)
  1967. if shrink:
  1968. ret.shrink_mask()
  1969. return ret
  1970. def masked_invalid(a, copy=True):
  1971. """
  1972. Mask an array where invalid values occur (NaNs or infs).
  1973. This function is a shortcut to ``masked_where``, with
  1974. `condition` = ~(np.isfinite(a)). Any pre-existing mask is conserved.
  1975. Only applies to arrays with a dtype where NaNs or infs make sense
  1976. (i.e. floating point types), but accepts any array_like object.
  1977. See Also
  1978. --------
  1979. masked_where : Mask where a condition is met.
  1980. Examples
  1981. --------
  1982. >>> import numpy as np
  1983. >>> import numpy.ma as ma
  1984. >>> a = np.arange(5, dtype=float)
  1985. >>> a[2] = np.nan
  1986. >>> a[3] = np.inf
  1987. >>> a
  1988. array([ 0., 1., nan, inf, 4.])
  1989. >>> ma.masked_invalid(a)
  1990. masked_array(data=[0.0, 1.0, --, --, 4.0],
  1991. mask=[False, False, True, True, False],
  1992. fill_value=1e+20)
  1993. """
  1994. a = np.array(a, copy=None, subok=True)
  1995. res = masked_where(~(np.isfinite(a)), a, copy=copy)
  1996. # masked_invalid previously never returned nomask as a mask and doing so
  1997. # threw off matplotlib (gh-22842). So use shrink=False:
  1998. if res._mask is nomask:
  1999. res._mask = make_mask_none(res.shape, res.dtype)
  2000. return res
  2001. ###############################################################################
  2002. # Printing options #
  2003. ###############################################################################
  2004. class _MaskedPrintOption:
  2005. """
  2006. Handle the string used to represent missing data in a masked array.
  2007. """
  2008. def __init__(self, display):
  2009. """
  2010. Create the masked_print_option object.
  2011. """
  2012. self._display = display
  2013. self._enabled = True
  2014. def display(self):
  2015. """
  2016. Display the string to print for masked values.
  2017. """
  2018. return self._display
  2019. def set_display(self, s):
  2020. """
  2021. Set the string to print for masked values.
  2022. """
  2023. self._display = s
  2024. def enabled(self):
  2025. """
  2026. Is the use of the display value enabled?
  2027. """
  2028. return self._enabled
  2029. def enable(self, shrink=1):
  2030. """
  2031. Set the enabling shrink to `shrink`.
  2032. """
  2033. self._enabled = shrink
  2034. def __str__(self):
  2035. return str(self._display)
  2036. __repr__ = __str__
  2037. # if you single index into a masked location you get this object.
  2038. masked_print_option = _MaskedPrintOption('--')
  2039. def _recursive_printoption(result, mask, printopt):
  2040. """
  2041. Puts printoptions in result where mask is True.
  2042. Private function allowing for recursion
  2043. """
  2044. names = result.dtype.names
  2045. if names is not None:
  2046. for name in names:
  2047. curdata = result[name]
  2048. curmask = mask[name]
  2049. _recursive_printoption(curdata, curmask, printopt)
  2050. else:
  2051. np.copyto(result, printopt, where=mask)
  2052. return
  2053. # For better or worse, these end in a newline
  2054. _legacy_print_templates = dict(
  2055. long_std=textwrap.dedent("""\
  2056. masked_%(name)s(data =
  2057. %(data)s,
  2058. %(nlen)s mask =
  2059. %(mask)s,
  2060. %(nlen)s fill_value = %(fill)s)
  2061. """),
  2062. long_flx=textwrap.dedent("""\
  2063. masked_%(name)s(data =
  2064. %(data)s,
  2065. %(nlen)s mask =
  2066. %(mask)s,
  2067. %(nlen)s fill_value = %(fill)s,
  2068. %(nlen)s dtype = %(dtype)s)
  2069. """),
  2070. short_std=textwrap.dedent("""\
  2071. masked_%(name)s(data = %(data)s,
  2072. %(nlen)s mask = %(mask)s,
  2073. %(nlen)s fill_value = %(fill)s)
  2074. """),
  2075. short_flx=textwrap.dedent("""\
  2076. masked_%(name)s(data = %(data)s,
  2077. %(nlen)s mask = %(mask)s,
  2078. %(nlen)s fill_value = %(fill)s,
  2079. %(nlen)s dtype = %(dtype)s)
  2080. """)
  2081. )
  2082. ###############################################################################
  2083. # MaskedArray class #
  2084. ###############################################################################
  2085. def _recursive_filled(a, mask, fill_value):
  2086. """
  2087. Recursively fill `a` with `fill_value`.
  2088. """
  2089. names = a.dtype.names
  2090. for name in names:
  2091. current = a[name]
  2092. if current.dtype.names is not None:
  2093. _recursive_filled(current, mask[name], fill_value[name])
  2094. else:
  2095. np.copyto(current, fill_value[name], where=mask[name])
  2096. def flatten_structured_array(a):
  2097. """
  2098. Flatten a structured array.
  2099. The data type of the output is chosen such that it can represent all of the
  2100. (nested) fields.
  2101. Parameters
  2102. ----------
  2103. a : structured array
  2104. Returns
  2105. -------
  2106. output : masked array or ndarray
  2107. A flattened masked array if the input is a masked array, otherwise a
  2108. standard ndarray.
  2109. Examples
  2110. --------
  2111. >>> import numpy as np
  2112. >>> ndtype = [('a', int), ('b', float)]
  2113. >>> a = np.array([(1, 1), (2, 2)], dtype=ndtype)
  2114. >>> np.ma.flatten_structured_array(a)
  2115. array([[1., 1.],
  2116. [2., 2.]])
  2117. """
  2118. def flatten_sequence(iterable):
  2119. """
  2120. Flattens a compound of nested iterables.
  2121. """
  2122. for elm in iter(iterable):
  2123. if hasattr(elm, '__iter__'):
  2124. yield from flatten_sequence(elm)
  2125. else:
  2126. yield elm
  2127. a = np.asanyarray(a)
  2128. inishape = a.shape
  2129. a = a.ravel()
  2130. if isinstance(a, MaskedArray):
  2131. out = np.array([tuple(flatten_sequence(d.item())) for d in a._data])
  2132. out = out.view(MaskedArray)
  2133. out._mask = np.array([tuple(flatten_sequence(d.item()))
  2134. for d in getmaskarray(a)])
  2135. else:
  2136. out = np.array([tuple(flatten_sequence(d.item())) for d in a])
  2137. if len(inishape) > 1:
  2138. newshape = list(out.shape)
  2139. newshape[0] = inishape
  2140. out.shape = tuple(flatten_sequence(newshape))
  2141. return out
  2142. def _arraymethod(funcname, onmask=True):
  2143. """
  2144. Return a class method wrapper around a basic array method.
  2145. Creates a class method which returns a masked array, where the new
  2146. ``_data`` array is the output of the corresponding basic method called
  2147. on the original ``_data``.
  2148. If `onmask` is True, the new mask is the output of the method called
  2149. on the initial mask. Otherwise, the new mask is just a reference
  2150. to the initial mask.
  2151. Parameters
  2152. ----------
  2153. funcname : str
  2154. Name of the function to apply on data.
  2155. onmask : bool
  2156. Whether the mask must be processed also (True) or left
  2157. alone (False). Default is True. Make available as `_onmask`
  2158. attribute.
  2159. Returns
  2160. -------
  2161. method : instancemethod
  2162. Class method wrapper of the specified basic array method.
  2163. """
  2164. def wrapped_method(self, *args, **params):
  2165. result = getattr(self._data, funcname)(*args, **params)
  2166. result = result.view(type(self))
  2167. result._update_from(self)
  2168. mask = self._mask
  2169. if not onmask:
  2170. result.__setmask__(mask)
  2171. elif mask is not nomask:
  2172. # __setmask__ makes a copy, which we don't want
  2173. result._mask = getattr(mask, funcname)(*args, **params)
  2174. return result
  2175. methdoc = getattr(ndarray, funcname, None) or getattr(np, funcname, None)
  2176. if methdoc is not None:
  2177. wrapped_method.__doc__ = methdoc.__doc__
  2178. wrapped_method.__name__ = funcname
  2179. return wrapped_method
  2180. class MaskedIterator:
  2181. """
  2182. Flat iterator object to iterate over masked arrays.
  2183. A `MaskedIterator` iterator is returned by ``x.flat`` for any masked array
  2184. `x`. It allows iterating over the array as if it were a 1-D array,
  2185. either in a for-loop or by calling its `next` method.
  2186. Iteration is done in C-contiguous style, with the last index varying the
  2187. fastest. The iterator can also be indexed using basic slicing or
  2188. advanced indexing.
  2189. See Also
  2190. --------
  2191. MaskedArray.flat : Return a flat iterator over an array.
  2192. MaskedArray.flatten : Returns a flattened copy of an array.
  2193. Notes
  2194. -----
  2195. `MaskedIterator` is not exported by the `ma` module. Instead of
  2196. instantiating a `MaskedIterator` directly, use `MaskedArray.flat`.
  2197. Examples
  2198. --------
  2199. >>> import numpy as np
  2200. >>> x = np.ma.array(arange(6).reshape(2, 3))
  2201. >>> fl = x.flat
  2202. >>> type(fl)
  2203. <class 'numpy.ma.MaskedIterator'>
  2204. >>> for item in fl:
  2205. ... print(item)
  2206. ...
  2207. 0
  2208. 1
  2209. 2
  2210. 3
  2211. 4
  2212. 5
  2213. Extracting more than a single element b indexing the `MaskedIterator`
  2214. returns a masked array:
  2215. >>> fl[2:4]
  2216. masked_array(data = [2 3],
  2217. mask = False,
  2218. fill_value = 999999)
  2219. """
  2220. def __init__(self, ma):
  2221. self.ma = ma
  2222. self.dataiter = ma._data.flat
  2223. if ma._mask is nomask:
  2224. self.maskiter = None
  2225. else:
  2226. self.maskiter = ma._mask.flat
  2227. def __iter__(self):
  2228. return self
  2229. def __getitem__(self, indx):
  2230. result = self.dataiter.__getitem__(indx).view(type(self.ma))
  2231. if self.maskiter is not None:
  2232. _mask = self.maskiter.__getitem__(indx)
  2233. if isinstance(_mask, ndarray):
  2234. # set shape to match that of data; this is needed for matrices
  2235. _mask.shape = result.shape
  2236. result._mask = _mask
  2237. elif isinstance(_mask, np.void):
  2238. return mvoid(result, mask=_mask, hardmask=self.ma._hardmask)
  2239. elif _mask: # Just a scalar, masked
  2240. return masked
  2241. return result
  2242. # This won't work if ravel makes a copy
  2243. def __setitem__(self, index, value):
  2244. self.dataiter[index] = getdata(value)
  2245. if self.maskiter is not None:
  2246. self.maskiter[index] = getmaskarray(value)
  2247. def __next__(self):
  2248. """
  2249. Return the next value, or raise StopIteration.
  2250. Examples
  2251. --------
  2252. >>> import numpy as np
  2253. >>> x = np.ma.array([3, 2], mask=[0, 1])
  2254. >>> fl = x.flat
  2255. >>> next(fl)
  2256. 3
  2257. >>> next(fl)
  2258. masked
  2259. >>> next(fl)
  2260. Traceback (most recent call last):
  2261. ...
  2262. StopIteration
  2263. """
  2264. d = next(self.dataiter)
  2265. if self.maskiter is not None:
  2266. m = next(self.maskiter)
  2267. if isinstance(m, np.void):
  2268. return mvoid(d, mask=m, hardmask=self.ma._hardmask)
  2269. elif m: # Just a scalar, masked
  2270. return masked
  2271. return d
  2272. @set_module("numpy.ma")
  2273. class MaskedArray(ndarray):
  2274. """
  2275. An array class with possibly masked values.
  2276. Masked values of True exclude the corresponding element from any
  2277. computation.
  2278. Construction::
  2279. x = MaskedArray(data, mask=nomask, dtype=None, copy=False, subok=True,
  2280. ndmin=0, fill_value=None, keep_mask=True, hard_mask=None,
  2281. shrink=True, order=None)
  2282. Parameters
  2283. ----------
  2284. data : array_like
  2285. Input data.
  2286. mask : sequence, optional
  2287. Mask. Must be convertible to an array of booleans with the same
  2288. shape as `data`. True indicates a masked (i.e. invalid) data.
  2289. dtype : dtype, optional
  2290. Data type of the output.
  2291. If `dtype` is None, the type of the data argument (``data.dtype``)
  2292. is used. If `dtype` is not None and different from ``data.dtype``,
  2293. a copy is performed.
  2294. copy : bool, optional
  2295. Whether to copy the input data (True), or to use a reference instead.
  2296. Default is False.
  2297. subok : bool, optional
  2298. Whether to return a subclass of `MaskedArray` if possible (True) or a
  2299. plain `MaskedArray`. Default is True.
  2300. ndmin : int, optional
  2301. Minimum number of dimensions. Default is 0.
  2302. fill_value : scalar, optional
  2303. Value used to fill in the masked values when necessary.
  2304. If None, a default based on the data-type is used.
  2305. keep_mask : bool, optional
  2306. Whether to combine `mask` with the mask of the input data, if any
  2307. (True), or to use only `mask` for the output (False). Default is True.
  2308. hard_mask : bool, optional
  2309. Whether to use a hard mask or not. With a hard mask, masked values
  2310. cannot be unmasked. Default is False.
  2311. shrink : bool, optional
  2312. Whether to force compression of an empty mask. Default is True.
  2313. order : {'C', 'F', 'A'}, optional
  2314. Specify the order of the array. If order is 'C', then the array
  2315. will be in C-contiguous order (last-index varies the fastest).
  2316. If order is 'F', then the returned array will be in
  2317. Fortran-contiguous order (first-index varies the fastest).
  2318. If order is 'A' (default), then the returned array may be
  2319. in any order (either C-, Fortran-contiguous, or even discontiguous),
  2320. unless a copy is required, in which case it will be C-contiguous.
  2321. Examples
  2322. --------
  2323. >>> import numpy as np
  2324. The ``mask`` can be initialized with an array of boolean values
  2325. with the same shape as ``data``.
  2326. >>> data = np.arange(6).reshape((2, 3))
  2327. >>> np.ma.MaskedArray(data, mask=[[False, True, False],
  2328. ... [False, False, True]])
  2329. masked_array(
  2330. data=[[0, --, 2],
  2331. [3, 4, --]],
  2332. mask=[[False, True, False],
  2333. [False, False, True]],
  2334. fill_value=999999)
  2335. Alternatively, the ``mask`` can be initialized to homogeneous boolean
  2336. array with the same shape as ``data`` by passing in a scalar
  2337. boolean value:
  2338. >>> np.ma.MaskedArray(data, mask=False)
  2339. masked_array(
  2340. data=[[0, 1, 2],
  2341. [3, 4, 5]],
  2342. mask=[[False, False, False],
  2343. [False, False, False]],
  2344. fill_value=999999)
  2345. >>> np.ma.MaskedArray(data, mask=True)
  2346. masked_array(
  2347. data=[[--, --, --],
  2348. [--, --, --]],
  2349. mask=[[ True, True, True],
  2350. [ True, True, True]],
  2351. fill_value=999999,
  2352. dtype=int64)
  2353. .. note::
  2354. The recommended practice for initializing ``mask`` with a scalar
  2355. boolean value is to use ``True``/``False`` rather than
  2356. ``np.True_``/``np.False_``. The reason is :attr:`nomask`
  2357. is represented internally as ``np.False_``.
  2358. >>> np.False_ is np.ma.nomask
  2359. True
  2360. """
  2361. __array_priority__ = 15
  2362. _defaultmask = nomask
  2363. _defaulthardmask = False
  2364. _baseclass = ndarray
  2365. # Maximum number of elements per axis used when printing an array. The
  2366. # 1d case is handled separately because we need more values in this case.
  2367. _print_width = 100
  2368. _print_width_1d = 1500
  2369. def __new__(cls, data=None, mask=nomask, dtype=None, copy=False,
  2370. subok=True, ndmin=0, fill_value=None, keep_mask=True,
  2371. hard_mask=None, shrink=True, order=None):
  2372. """
  2373. Create a new masked array from scratch.
  2374. Notes
  2375. -----
  2376. A masked array can also be created by taking a .view(MaskedArray).
  2377. """
  2378. # Process data.
  2379. copy = None if not copy else True
  2380. _data = np.array(data, dtype=dtype, copy=copy,
  2381. order=order, subok=True, ndmin=ndmin)
  2382. _baseclass = getattr(data, '_baseclass', type(_data))
  2383. # Check that we're not erasing the mask.
  2384. if isinstance(data, MaskedArray) and (data.shape != _data.shape):
  2385. copy = True
  2386. # Here, we copy the _view_, so that we can attach new properties to it
  2387. # we must never do .view(MaskedConstant), as that would create a new
  2388. # instance of np.ma.masked, which make identity comparison fail
  2389. if isinstance(data, cls) and subok and not isinstance(data, MaskedConstant):
  2390. _data = ndarray.view(_data, type(data))
  2391. else:
  2392. _data = ndarray.view(_data, cls)
  2393. # Handle the case where data is not a subclass of ndarray, but
  2394. # still has the _mask attribute like MaskedArrays
  2395. if hasattr(data, '_mask') and not isinstance(data, ndarray):
  2396. _data._mask = data._mask
  2397. # FIXME: should we set `_data._sharedmask = True`?
  2398. # Process mask.
  2399. # Type of the mask
  2400. mdtype = make_mask_descr(_data.dtype)
  2401. if mask is nomask:
  2402. # Case 1. : no mask in input.
  2403. # Erase the current mask ?
  2404. if not keep_mask:
  2405. # With a reduced version
  2406. if shrink:
  2407. _data._mask = nomask
  2408. # With full version
  2409. else:
  2410. _data._mask = np.zeros(_data.shape, dtype=mdtype)
  2411. # Check whether we missed something
  2412. elif isinstance(data, (tuple, list)):
  2413. try:
  2414. # If data is a sequence of masked array
  2415. mask = np.array(
  2416. [getmaskarray(np.asanyarray(m, dtype=_data.dtype))
  2417. for m in data], dtype=mdtype)
  2418. except (ValueError, TypeError):
  2419. # If data is nested
  2420. mask = nomask
  2421. # Force shrinking of the mask if needed (and possible)
  2422. if (mdtype == MaskType) and mask.any():
  2423. _data._mask = mask
  2424. _data._sharedmask = False
  2425. else:
  2426. _data._sharedmask = not copy
  2427. if copy:
  2428. _data._mask = _data._mask.copy()
  2429. # Reset the shape of the original mask
  2430. if getmask(data) is not nomask:
  2431. # gh-21022 encounters an issue here
  2432. # because data._mask.shape is not writeable, but
  2433. # the op was also pointless in that case, because
  2434. # the shapes were the same, so we can at least
  2435. # avoid that path
  2436. if data._mask.shape != data.shape:
  2437. data._mask.shape = data.shape
  2438. else:
  2439. # Case 2. : With a mask in input.
  2440. # If mask is boolean, create an array of True or False
  2441. # if users pass `mask=None` be forgiving here and cast it False
  2442. # for speed; although the default is `mask=nomask` and can differ.
  2443. if mask is None:
  2444. mask = False
  2445. if mask is True and mdtype == MaskType:
  2446. mask = np.ones(_data.shape, dtype=mdtype)
  2447. elif mask is False and mdtype == MaskType:
  2448. mask = np.zeros(_data.shape, dtype=mdtype)
  2449. else:
  2450. # Read the mask with the current mdtype
  2451. try:
  2452. mask = np.array(mask, copy=copy, dtype=mdtype)
  2453. # Or assume it's a sequence of bool/int
  2454. except TypeError:
  2455. mask = np.array([tuple([m] * len(mdtype)) for m in mask],
  2456. dtype=mdtype)
  2457. # Make sure the mask and the data have the same shape
  2458. if mask.shape != _data.shape:
  2459. (nd, nm) = (_data.size, mask.size)
  2460. if nm == 1:
  2461. mask = np.resize(mask, _data.shape)
  2462. elif nm == nd:
  2463. mask = np.reshape(mask, _data.shape)
  2464. else:
  2465. msg = "Mask and data not compatible: data size is %i, " + \
  2466. "mask size is %i."
  2467. raise MaskError(msg % (nd, nm))
  2468. copy = True
  2469. # Set the mask to the new value
  2470. if _data._mask is nomask:
  2471. _data._mask = mask
  2472. _data._sharedmask = not copy
  2473. else:
  2474. if not keep_mask:
  2475. _data._mask = mask
  2476. _data._sharedmask = not copy
  2477. else:
  2478. if _data.dtype.names is not None:
  2479. def _recursive_or(a, b):
  2480. "do a|=b on each field of a, recursively"
  2481. for name in a.dtype.names:
  2482. (af, bf) = (a[name], b[name])
  2483. if af.dtype.names is not None:
  2484. _recursive_or(af, bf)
  2485. else:
  2486. af |= bf
  2487. _recursive_or(_data._mask, mask)
  2488. else:
  2489. _data._mask = np.logical_or(mask, _data._mask)
  2490. _data._sharedmask = False
  2491. # Update fill_value.
  2492. if fill_value is None:
  2493. fill_value = getattr(data, '_fill_value', None)
  2494. # But don't run the check unless we have something to check.
  2495. if fill_value is not None:
  2496. _data._fill_value = _check_fill_value(fill_value, _data.dtype)
  2497. # Process extra options ..
  2498. if hard_mask is None:
  2499. _data._hardmask = getattr(data, '_hardmask', False)
  2500. else:
  2501. _data._hardmask = hard_mask
  2502. _data._baseclass = _baseclass
  2503. return _data
  2504. def _update_from(self, obj):
  2505. """
  2506. Copies some attributes of obj to self.
  2507. """
  2508. if isinstance(obj, ndarray):
  2509. _baseclass = type(obj)
  2510. else:
  2511. _baseclass = ndarray
  2512. # We need to copy the _basedict to avoid backward propagation
  2513. _optinfo = {}
  2514. _optinfo.update(getattr(obj, '_optinfo', {}))
  2515. _optinfo.update(getattr(obj, '_basedict', {}))
  2516. if not isinstance(obj, MaskedArray):
  2517. _optinfo.update(getattr(obj, '__dict__', {}))
  2518. _dict = dict(_fill_value=getattr(obj, '_fill_value', None),
  2519. _hardmask=getattr(obj, '_hardmask', False),
  2520. _sharedmask=getattr(obj, '_sharedmask', False),
  2521. _isfield=getattr(obj, '_isfield', False),
  2522. _baseclass=getattr(obj, '_baseclass', _baseclass),
  2523. _optinfo=_optinfo,
  2524. _basedict=_optinfo)
  2525. self.__dict__.update(_dict)
  2526. self.__dict__.update(_optinfo)
  2527. return
  2528. def __array_finalize__(self, obj):
  2529. """
  2530. Finalizes the masked array.
  2531. """
  2532. # Get main attributes.
  2533. self._update_from(obj)
  2534. # We have to decide how to initialize self.mask, based on
  2535. # obj.mask. This is very difficult. There might be some
  2536. # correspondence between the elements in the array we are being
  2537. # created from (= obj) and us. Or there might not. This method can
  2538. # be called in all kinds of places for all kinds of reasons -- could
  2539. # be empty_like, could be slicing, could be a ufunc, could be a view.
  2540. # The numpy subclassing interface simply doesn't give us any way
  2541. # to know, which means that at best this method will be based on
  2542. # guesswork and heuristics. To make things worse, there isn't even any
  2543. # clear consensus about what the desired behavior is. For instance,
  2544. # most users think that np.empty_like(marr) -- which goes via this
  2545. # method -- should return a masked array with an empty mask (see
  2546. # gh-3404 and linked discussions), but others disagree, and they have
  2547. # existing code which depends on empty_like returning an array that
  2548. # matches the input mask.
  2549. #
  2550. # Historically our algorithm was: if the template object mask had the
  2551. # same *number of elements* as us, then we used *it's mask object
  2552. # itself* as our mask, so that writes to us would also write to the
  2553. # original array. This is horribly broken in multiple ways.
  2554. #
  2555. # Now what we do instead is, if the template object mask has the same
  2556. # number of elements as us, and we do not have the same base pointer
  2557. # as the template object (b/c views like arr[...] should keep the same
  2558. # mask), then we make a copy of the template object mask and use
  2559. # that. This is also horribly broken but somewhat less so. Maybe.
  2560. if isinstance(obj, ndarray):
  2561. # XX: This looks like a bug -- shouldn't it check self.dtype
  2562. # instead?
  2563. if obj.dtype.names is not None:
  2564. _mask = getmaskarray(obj)
  2565. else:
  2566. _mask = getmask(obj)
  2567. # If self and obj point to exactly the same data, then probably
  2568. # self is a simple view of obj (e.g., self = obj[...]), so they
  2569. # should share the same mask. (This isn't 100% reliable, e.g. self
  2570. # could be the first row of obj, or have strange strides, but as a
  2571. # heuristic it's not bad.) In all other cases, we make a copy of
  2572. # the mask, so that future modifications to 'self' do not end up
  2573. # side-effecting 'obj' as well.
  2574. if (_mask is not nomask and obj.__array_interface__["data"][0]
  2575. != self.__array_interface__["data"][0]):
  2576. # We should make a copy. But we could get here via astype,
  2577. # in which case the mask might need a new dtype as well
  2578. # (e.g., changing to or from a structured dtype), and the
  2579. # order could have changed. So, change the mask type if
  2580. # needed and use astype instead of copy.
  2581. if self.dtype == obj.dtype:
  2582. _mask_dtype = _mask.dtype
  2583. else:
  2584. _mask_dtype = make_mask_descr(self.dtype)
  2585. if self.flags.c_contiguous:
  2586. order = "C"
  2587. elif self.flags.f_contiguous:
  2588. order = "F"
  2589. else:
  2590. order = "K"
  2591. _mask = _mask.astype(_mask_dtype, order)
  2592. else:
  2593. # Take a view so shape changes, etc., do not propagate back.
  2594. _mask = _mask.view()
  2595. else:
  2596. _mask = nomask
  2597. self._mask = _mask
  2598. # Finalize the mask
  2599. if self._mask is not nomask:
  2600. try:
  2601. self._mask.shape = self.shape
  2602. except ValueError:
  2603. self._mask = nomask
  2604. except (TypeError, AttributeError):
  2605. # When _mask.shape is not writable (because it's a void)
  2606. pass
  2607. # Finalize the fill_value
  2608. if self._fill_value is not None:
  2609. self._fill_value = _check_fill_value(self._fill_value, self.dtype)
  2610. elif self.dtype.names is not None:
  2611. # Finalize the default fill_value for structured arrays
  2612. self._fill_value = _check_fill_value(None, self.dtype)
  2613. def __array_wrap__(self, obj, context=None, return_scalar=False):
  2614. """
  2615. Special hook for ufuncs.
  2616. Wraps the numpy array and sets the mask according to context.
  2617. """
  2618. if obj is self: # for in-place operations
  2619. result = obj
  2620. else:
  2621. result = obj.view(type(self))
  2622. result._update_from(self)
  2623. if context is not None:
  2624. result._mask = result._mask.copy()
  2625. func, args, out_i = context
  2626. # args sometimes contains outputs (gh-10459), which we don't want
  2627. input_args = args[:func.nin]
  2628. m = functools.reduce(mask_or, [getmaskarray(arg) for arg in input_args])
  2629. # Get the domain mask
  2630. domain = ufunc_domain.get(func)
  2631. if domain is not None:
  2632. # Take the domain, and make sure it's a ndarray
  2633. with np.errstate(divide='ignore', invalid='ignore'):
  2634. # The result may be masked for two (unary) domains.
  2635. # That can't really be right as some domains drop
  2636. # the mask and some don't behaving differently here.
  2637. d = domain(*input_args).astype(bool, copy=False)
  2638. d = filled(d, True)
  2639. if d.any():
  2640. # Fill the result where the domain is wrong
  2641. try:
  2642. # Binary domain: take the last value
  2643. fill_value = ufunc_fills[func][-1]
  2644. except TypeError:
  2645. # Unary domain: just use this one
  2646. fill_value = ufunc_fills[func]
  2647. except KeyError:
  2648. # Domain not recognized, use fill_value instead
  2649. fill_value = self.fill_value
  2650. np.copyto(result, fill_value, where=d)
  2651. # Update the mask
  2652. if m is nomask:
  2653. m = d
  2654. else:
  2655. # Don't modify inplace, we risk back-propagation
  2656. m = (m | d)
  2657. # Make sure the mask has the proper size
  2658. if result is not self and result.shape == () and m:
  2659. return masked
  2660. else:
  2661. result._mask = m
  2662. result._sharedmask = False
  2663. return result
  2664. def view(self, dtype=None, type=None, fill_value=None):
  2665. """
  2666. Return a view of the MaskedArray data.
  2667. Parameters
  2668. ----------
  2669. dtype : data-type or ndarray sub-class, optional
  2670. Data-type descriptor of the returned view, e.g., float32 or int16.
  2671. The default, None, results in the view having the same data-type
  2672. as `a`. As with ``ndarray.view``, dtype can also be specified as
  2673. an ndarray sub-class, which then specifies the type of the
  2674. returned object (this is equivalent to setting the ``type``
  2675. parameter).
  2676. type : Python type, optional
  2677. Type of the returned view, either ndarray or a subclass. The
  2678. default None results in type preservation.
  2679. fill_value : scalar, optional
  2680. The value to use for invalid entries (None by default).
  2681. If None, then this argument is inferred from the passed `dtype`, or
  2682. in its absence the original array, as discussed in the notes below.
  2683. See Also
  2684. --------
  2685. numpy.ndarray.view : Equivalent method on ndarray object.
  2686. Notes
  2687. -----
  2688. ``a.view()`` is used two different ways:
  2689. ``a.view(some_dtype)`` or ``a.view(dtype=some_dtype)`` constructs a view
  2690. of the array's memory with a different data-type. This can cause a
  2691. reinterpretation of the bytes of memory.
  2692. ``a.view(ndarray_subclass)`` or ``a.view(type=ndarray_subclass)`` just
  2693. returns an instance of `ndarray_subclass` that looks at the same array
  2694. (same shape, dtype, etc.) This does not cause a reinterpretation of the
  2695. memory.
  2696. If `fill_value` is not specified, but `dtype` is specified (and is not
  2697. an ndarray sub-class), the `fill_value` of the MaskedArray will be
  2698. reset. If neither `fill_value` nor `dtype` are specified (or if
  2699. `dtype` is an ndarray sub-class), then the fill value is preserved.
  2700. Finally, if `fill_value` is specified, but `dtype` is not, the fill
  2701. value is set to the specified value.
  2702. For ``a.view(some_dtype)``, if ``some_dtype`` has a different number of
  2703. bytes per entry than the previous dtype (for example, converting a
  2704. regular array to a structured array), then the behavior of the view
  2705. cannot be predicted just from the superficial appearance of ``a`` (shown
  2706. by ``print(a)``). It also depends on exactly how ``a`` is stored in
  2707. memory. Therefore if ``a`` is C-ordered versus fortran-ordered, versus
  2708. defined as a slice or transpose, etc., the view may give different
  2709. results.
  2710. """
  2711. if dtype is None:
  2712. if type is None:
  2713. output = ndarray.view(self)
  2714. else:
  2715. output = ndarray.view(self, type)
  2716. elif type is None:
  2717. try:
  2718. if issubclass(dtype, ndarray):
  2719. output = ndarray.view(self, dtype)
  2720. dtype = None
  2721. else:
  2722. output = ndarray.view(self, dtype)
  2723. except TypeError:
  2724. output = ndarray.view(self, dtype)
  2725. else:
  2726. output = ndarray.view(self, dtype, type)
  2727. # also make the mask be a view (so attr changes to the view's
  2728. # mask do no affect original object's mask)
  2729. # (especially important to avoid affecting np.masked singleton)
  2730. if getmask(output) is not nomask:
  2731. output._mask = output._mask.view()
  2732. # Make sure to reset the _fill_value if needed
  2733. if getattr(output, '_fill_value', None) is not None:
  2734. if fill_value is None:
  2735. if dtype is None:
  2736. pass # leave _fill_value as is
  2737. else:
  2738. output._fill_value = None
  2739. else:
  2740. output.fill_value = fill_value
  2741. return output
  2742. def __getitem__(self, indx):
  2743. """
  2744. x.__getitem__(y) <==> x[y]
  2745. Return the item described by i, as a masked array.
  2746. """
  2747. # We could directly use ndarray.__getitem__ on self.
  2748. # But then we would have to modify __array_finalize__ to prevent the
  2749. # mask of being reshaped if it hasn't been set up properly yet
  2750. # So it's easier to stick to the current version
  2751. dout = self.data[indx]
  2752. _mask = self._mask
  2753. def _is_scalar(m):
  2754. return not isinstance(m, np.ndarray)
  2755. def _scalar_heuristic(arr, elem):
  2756. """
  2757. Return whether `elem` is a scalar result of indexing `arr`, or None
  2758. if undecidable without promoting nomask to a full mask
  2759. """
  2760. # obviously a scalar
  2761. if not isinstance(elem, np.ndarray):
  2762. return True
  2763. # object array scalar indexing can return anything
  2764. elif arr.dtype.type is np.object_:
  2765. if arr.dtype is not elem.dtype:
  2766. # elem is an array, but dtypes do not match, so must be
  2767. # an element
  2768. return True
  2769. # well-behaved subclass that only returns 0d arrays when
  2770. # expected - this is not a scalar
  2771. elif type(arr).__getitem__ == ndarray.__getitem__:
  2772. return False
  2773. return None
  2774. if _mask is not nomask:
  2775. # _mask cannot be a subclass, so it tells us whether we should
  2776. # expect a scalar. It also cannot be of dtype object.
  2777. mout = _mask[indx]
  2778. scalar_expected = _is_scalar(mout)
  2779. else:
  2780. # attempt to apply the heuristic to avoid constructing a full mask
  2781. mout = nomask
  2782. scalar_expected = _scalar_heuristic(self.data, dout)
  2783. if scalar_expected is None:
  2784. # heuristics have failed
  2785. # construct a full array, so we can be certain. This is costly.
  2786. # we could also fall back on ndarray.__getitem__(self.data, indx)
  2787. scalar_expected = _is_scalar(getmaskarray(self)[indx])
  2788. # Did we extract a single item?
  2789. if scalar_expected:
  2790. # A record
  2791. if isinstance(dout, np.void):
  2792. # We should always re-cast to mvoid, otherwise users can
  2793. # change masks on rows that already have masked values, but not
  2794. # on rows that have no masked values, which is inconsistent.
  2795. return mvoid(dout, mask=mout, hardmask=self._hardmask)
  2796. # special case introduced in gh-5962
  2797. elif (self.dtype.type is np.object_ and
  2798. isinstance(dout, np.ndarray) and
  2799. dout is not masked):
  2800. # If masked, turn into a MaskedArray, with everything masked.
  2801. if mout:
  2802. return MaskedArray(dout, mask=True)
  2803. else:
  2804. return dout
  2805. # Just a scalar
  2806. else:
  2807. if mout:
  2808. return masked
  2809. else:
  2810. return dout
  2811. else:
  2812. # Force dout to MA
  2813. dout = dout.view(type(self))
  2814. # Inherit attributes from self
  2815. dout._update_from(self)
  2816. # Check the fill_value
  2817. if is_string_or_list_of_strings(indx):
  2818. if self._fill_value is not None:
  2819. dout._fill_value = self._fill_value[indx]
  2820. # Something like gh-15895 has happened if this check fails.
  2821. # _fill_value should always be an ndarray.
  2822. if not isinstance(dout._fill_value, np.ndarray):
  2823. raise RuntimeError('Internal NumPy error.')
  2824. # If we're indexing a multidimensional field in a
  2825. # structured array (such as dtype("(2,)i2,(2,)i1")),
  2826. # dimensionality goes up (M[field].ndim == M.ndim +
  2827. # M.dtype[field].ndim). That's fine for
  2828. # M[field] but problematic for M[field].fill_value
  2829. # which should have shape () to avoid breaking several
  2830. # methods. There is no great way out, so set to
  2831. # first element. See issue #6723.
  2832. if dout._fill_value.ndim > 0:
  2833. if not (dout._fill_value ==
  2834. dout._fill_value.flat[0]).all():
  2835. warnings.warn(
  2836. "Upon accessing multidimensional field "
  2837. f"{indx!s}, need to keep dimensionality "
  2838. "of fill_value at 0. Discarding "
  2839. "heterogeneous fill_value and setting "
  2840. f"all to {dout._fill_value[0]!s}.",
  2841. stacklevel=2)
  2842. # Need to use `.flat[0:1].squeeze(...)` instead of just
  2843. # `.flat[0]` to ensure the result is a 0d array and not
  2844. # a scalar.
  2845. dout._fill_value = dout._fill_value.flat[0:1].squeeze(axis=0)
  2846. dout._isfield = True
  2847. # Update the mask if needed
  2848. if mout is not nomask:
  2849. # set shape to match that of data; this is needed for matrices
  2850. dout._mask = reshape(mout, dout.shape)
  2851. dout._sharedmask = True
  2852. # Note: Don't try to check for m.any(), that'll take too long
  2853. return dout
  2854. # setitem may put NaNs into integer arrays or occasionally overflow a
  2855. # float. But this may happen in masked values, so avoid otherwise
  2856. # correct warnings (as is typical also in masked calculations).
  2857. @np.errstate(over='ignore', invalid='ignore')
  2858. def __setitem__(self, indx, value):
  2859. """
  2860. x.__setitem__(i, y) <==> x[i]=y
  2861. Set item described by index. If value is masked, masks those
  2862. locations.
  2863. """
  2864. if self is masked:
  2865. raise MaskError('Cannot alter the masked element.')
  2866. _data = self._data
  2867. _mask = self._mask
  2868. if isinstance(indx, str):
  2869. _data[indx] = value
  2870. if _mask is nomask:
  2871. self._mask = _mask = make_mask_none(self.shape, self.dtype)
  2872. _mask[indx] = getmask(value)
  2873. return
  2874. _dtype = _data.dtype
  2875. if value is masked:
  2876. # The mask wasn't set: create a full version.
  2877. if _mask is nomask:
  2878. _mask = self._mask = make_mask_none(self.shape, _dtype)
  2879. # Now, set the mask to its value.
  2880. if _dtype.names is not None:
  2881. _mask[indx] = tuple([True] * len(_dtype.names))
  2882. else:
  2883. _mask[indx] = True
  2884. return
  2885. # Get the _data part of the new value
  2886. dval = getattr(value, '_data', value)
  2887. # Get the _mask part of the new value
  2888. mval = getmask(value)
  2889. if _dtype.names is not None and mval is nomask:
  2890. mval = tuple([False] * len(_dtype.names))
  2891. if _mask is nomask:
  2892. # Set the data, then the mask
  2893. _data[indx] = dval
  2894. if mval is not nomask:
  2895. _mask = self._mask = make_mask_none(self.shape, _dtype)
  2896. _mask[indx] = mval
  2897. elif not self._hardmask:
  2898. # Set the data, then the mask
  2899. if (isinstance(indx, masked_array) and
  2900. not isinstance(value, masked_array)):
  2901. _data[indx.data] = dval
  2902. else:
  2903. _data[indx] = dval
  2904. _mask[indx] = mval
  2905. elif hasattr(indx, 'dtype') and (indx.dtype == MaskType):
  2906. indx = indx * umath.logical_not(_mask)
  2907. _data[indx] = dval
  2908. else:
  2909. if _dtype.names is not None:
  2910. err_msg = "Flexible 'hard' masks are not yet supported."
  2911. raise NotImplementedError(err_msg)
  2912. mindx = mask_or(_mask[indx], mval, copy=True)
  2913. dindx = self._data[indx]
  2914. if dindx.size > 1:
  2915. np.copyto(dindx, dval, where=~mindx)
  2916. elif mindx is nomask:
  2917. dindx = dval
  2918. _data[indx] = dindx
  2919. _mask[indx] = mindx
  2920. return
  2921. # Define so that we can overwrite the setter.
  2922. @property
  2923. def dtype(self):
  2924. return super().dtype
  2925. @dtype.setter
  2926. def dtype(self, dtype):
  2927. super(MaskedArray, type(self)).dtype.__set__(self, dtype)
  2928. if self._mask is not nomask:
  2929. self._mask = self._mask.view(make_mask_descr(dtype), ndarray)
  2930. # Try to reset the shape of the mask (if we don't have a void).
  2931. # This raises a ValueError if the dtype change won't work.
  2932. try:
  2933. self._mask.shape = self.shape
  2934. except (AttributeError, TypeError):
  2935. pass
  2936. @property
  2937. def shape(self):
  2938. return super().shape
  2939. @shape.setter
  2940. def shape(self, shape):
  2941. super(MaskedArray, type(self)).shape.__set__(self, shape)
  2942. # Cannot use self._mask, since it may not (yet) exist when a
  2943. # masked matrix sets the shape.
  2944. if getmask(self) is not nomask:
  2945. self._mask.shape = self.shape
  2946. def __setmask__(self, mask, copy=False):
  2947. """
  2948. Set the mask.
  2949. """
  2950. idtype = self.dtype
  2951. current_mask = self._mask
  2952. if mask is masked:
  2953. mask = True
  2954. if current_mask is nomask:
  2955. # Make sure the mask is set
  2956. # Just don't do anything if there's nothing to do.
  2957. if mask is nomask:
  2958. return
  2959. current_mask = self._mask = make_mask_none(self.shape, idtype)
  2960. if idtype.names is None:
  2961. # No named fields.
  2962. # Hardmask: don't unmask the data
  2963. if self._hardmask:
  2964. current_mask |= mask
  2965. # Softmask: set everything to False
  2966. # If it's obviously a compatible scalar, use a quick update
  2967. # method.
  2968. elif isinstance(mask, (int, float, np.bool, np.number)):
  2969. current_mask[...] = mask
  2970. # Otherwise fall back to the slower, general purpose way.
  2971. else:
  2972. current_mask.flat = mask
  2973. else:
  2974. # Named fields w/
  2975. mdtype = current_mask.dtype
  2976. mask = np.asarray(mask)
  2977. # Mask is a singleton
  2978. if not mask.ndim:
  2979. # It's a boolean : make a record
  2980. if mask.dtype.kind == 'b':
  2981. mask = np.array(tuple([mask.item()] * len(mdtype)),
  2982. dtype=mdtype)
  2983. # It's a record: make sure the dtype is correct
  2984. else:
  2985. mask = mask.astype(mdtype)
  2986. # Mask is a sequence
  2987. else:
  2988. # Make sure the new mask is a ndarray with the proper dtype
  2989. try:
  2990. copy = None if not copy else True
  2991. mask = np.array(mask, copy=copy, dtype=mdtype)
  2992. # Or assume it's a sequence of bool/int
  2993. except TypeError:
  2994. mask = np.array([tuple([m] * len(mdtype)) for m in mask],
  2995. dtype=mdtype)
  2996. # Hardmask: don't unmask the data
  2997. if self._hardmask:
  2998. for n in idtype.names:
  2999. current_mask[n] |= mask[n]
  3000. # Softmask: set everything to False
  3001. # If it's obviously a compatible scalar, use a quick update
  3002. # method.
  3003. elif isinstance(mask, (int, float, np.bool, np.number)):
  3004. current_mask[...] = mask
  3005. # Otherwise fall back to the slower, general purpose way.
  3006. else:
  3007. current_mask.flat = mask
  3008. # Reshape if needed
  3009. if current_mask.shape:
  3010. current_mask.shape = self.shape
  3011. return
  3012. _set_mask = __setmask__
  3013. @property
  3014. def mask(self):
  3015. """ Current mask. """
  3016. # We could try to force a reshape, but that wouldn't work in some
  3017. # cases.
  3018. # Return a view so that the dtype and shape cannot be changed in place
  3019. # This still preserves nomask by identity
  3020. return self._mask.view()
  3021. @mask.setter
  3022. def mask(self, value):
  3023. self.__setmask__(value)
  3024. @property
  3025. def recordmask(self):
  3026. """
  3027. Get or set the mask of the array if it has no named fields. For
  3028. structured arrays, returns a ndarray of booleans where entries are
  3029. ``True`` if **all** the fields are masked, ``False`` otherwise:
  3030. >>> x = np.ma.array([(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)],
  3031. ... mask=[(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)],
  3032. ... dtype=[('a', int), ('b', int)])
  3033. >>> x.recordmask
  3034. array([False, False, True, False, False])
  3035. """
  3036. _mask = self._mask.view(ndarray)
  3037. if _mask.dtype.names is None:
  3038. return _mask
  3039. return np.all(flatten_structured_array(_mask), axis=-1)
  3040. @recordmask.setter
  3041. def recordmask(self, mask):
  3042. raise NotImplementedError("Coming soon: setting the mask per records!")
  3043. def harden_mask(self):
  3044. """
  3045. Force the mask to hard, preventing unmasking by assignment.
  3046. Whether the mask of a masked array is hard or soft is determined by
  3047. its `~ma.MaskedArray.hardmask` property. `harden_mask` sets
  3048. `~ma.MaskedArray.hardmask` to ``True`` (and returns the modified
  3049. self).
  3050. See Also
  3051. --------
  3052. ma.MaskedArray.hardmask
  3053. ma.MaskedArray.soften_mask
  3054. """
  3055. self._hardmask = True
  3056. return self
  3057. def soften_mask(self):
  3058. """
  3059. Force the mask to soft (default), allowing unmasking by assignment.
  3060. Whether the mask of a masked array is hard or soft is determined by
  3061. its `~ma.MaskedArray.hardmask` property. `soften_mask` sets
  3062. `~ma.MaskedArray.hardmask` to ``False`` (and returns the modified
  3063. self).
  3064. See Also
  3065. --------
  3066. ma.MaskedArray.hardmask
  3067. ma.MaskedArray.harden_mask
  3068. """
  3069. self._hardmask = False
  3070. return self
  3071. @property
  3072. def hardmask(self):
  3073. """
  3074. Specifies whether values can be unmasked through assignments.
  3075. By default, assigning definite values to masked array entries will
  3076. unmask them. When `hardmask` is ``True``, the mask will not change
  3077. through assignments.
  3078. See Also
  3079. --------
  3080. ma.MaskedArray.harden_mask
  3081. ma.MaskedArray.soften_mask
  3082. Examples
  3083. --------
  3084. >>> import numpy as np
  3085. >>> x = np.arange(10)
  3086. >>> m = np.ma.masked_array(x, x>5)
  3087. >>> assert not m.hardmask
  3088. Since `m` has a soft mask, assigning an element value unmasks that
  3089. element:
  3090. >>> m[8] = 42
  3091. >>> m
  3092. masked_array(data=[0, 1, 2, 3, 4, 5, --, --, 42, --],
  3093. mask=[False, False, False, False, False, False,
  3094. True, True, False, True],
  3095. fill_value=999999)
  3096. After hardening, the mask is not affected by assignments:
  3097. >>> hardened = np.ma.harden_mask(m)
  3098. >>> assert m.hardmask and hardened is m
  3099. >>> m[:] = 23
  3100. >>> m
  3101. masked_array(data=[23, 23, 23, 23, 23, 23, --, --, 23, --],
  3102. mask=[False, False, False, False, False, False,
  3103. True, True, False, True],
  3104. fill_value=999999)
  3105. """
  3106. return self._hardmask
  3107. def unshare_mask(self):
  3108. """
  3109. Copy the mask and set the `sharedmask` flag to ``False``.
  3110. Whether the mask is shared between masked arrays can be seen from
  3111. the `sharedmask` property. `unshare_mask` ensures the mask is not
  3112. shared. A copy of the mask is only made if it was shared.
  3113. See Also
  3114. --------
  3115. sharedmask
  3116. """
  3117. if self._sharedmask:
  3118. self._mask = self._mask.copy()
  3119. self._sharedmask = False
  3120. return self
  3121. @property
  3122. def sharedmask(self):
  3123. """ Share status of the mask (read-only). """
  3124. return self._sharedmask
  3125. def shrink_mask(self):
  3126. """
  3127. Reduce a mask to nomask when possible.
  3128. Parameters
  3129. ----------
  3130. None
  3131. Returns
  3132. -------
  3133. None
  3134. Examples
  3135. --------
  3136. >>> import numpy as np
  3137. >>> x = np.ma.array([[1,2 ], [3, 4]], mask=[0]*4)
  3138. >>> x.mask
  3139. array([[False, False],
  3140. [False, False]])
  3141. >>> x.shrink_mask()
  3142. masked_array(
  3143. data=[[1, 2],
  3144. [3, 4]],
  3145. mask=False,
  3146. fill_value=999999)
  3147. >>> x.mask
  3148. False
  3149. """
  3150. self._mask = _shrink_mask(self._mask)
  3151. return self
  3152. @property
  3153. def baseclass(self):
  3154. """ Class of the underlying data (read-only). """
  3155. return self._baseclass
  3156. def _get_data(self):
  3157. """
  3158. Returns the underlying data, as a view of the masked array.
  3159. If the underlying data is a subclass of :class:`numpy.ndarray`, it is
  3160. returned as such.
  3161. >>> x = np.ma.array(np.matrix([[1, 2], [3, 4]]), mask=[[0, 1], [1, 0]])
  3162. >>> x.data
  3163. matrix([[1, 2],
  3164. [3, 4]])
  3165. The type of the data can be accessed through the :attr:`baseclass`
  3166. attribute.
  3167. """
  3168. return ndarray.view(self, self._baseclass)
  3169. _data = property(fget=_get_data)
  3170. data = property(fget=_get_data)
  3171. @property
  3172. def flat(self):
  3173. """ Return a flat iterator, or set a flattened version of self to value. """
  3174. return MaskedIterator(self)
  3175. @flat.setter
  3176. def flat(self, value):
  3177. y = self.ravel()
  3178. y[:] = value
  3179. @property
  3180. def fill_value(self):
  3181. """
  3182. The filling value of the masked array is a scalar. When setting, None
  3183. will set to a default based on the data type.
  3184. Examples
  3185. --------
  3186. >>> import numpy as np
  3187. >>> for dt in [np.int32, np.int64, np.float64, np.complex128]:
  3188. ... np.ma.array([0, 1], dtype=dt).get_fill_value()
  3189. ...
  3190. np.int64(999999)
  3191. np.int64(999999)
  3192. np.float64(1e+20)
  3193. np.complex128(1e+20+0j)
  3194. >>> x = np.ma.array([0, 1.], fill_value=-np.inf)
  3195. >>> x.fill_value
  3196. np.float64(-inf)
  3197. >>> x.fill_value = np.pi
  3198. >>> x.fill_value
  3199. np.float64(3.1415926535897931)
  3200. Reset to default:
  3201. >>> x.fill_value = None
  3202. >>> x.fill_value
  3203. np.float64(1e+20)
  3204. """
  3205. if self._fill_value is None:
  3206. self._fill_value = _check_fill_value(None, self.dtype)
  3207. # Temporary workaround to account for the fact that str and bytes
  3208. # scalars cannot be indexed with (), whereas all other numpy
  3209. # scalars can. See issues #7259 and #7267.
  3210. # The if-block can be removed after #7267 has been fixed.
  3211. if isinstance(self._fill_value, ndarray):
  3212. return self._fill_value[()]
  3213. return self._fill_value
  3214. @fill_value.setter
  3215. def fill_value(self, value=None):
  3216. target = _check_fill_value(value, self.dtype)
  3217. if not target.ndim == 0:
  3218. # 2019-11-12, 1.18.0
  3219. warnings.warn(
  3220. "Non-scalar arrays for the fill value are deprecated. Use "
  3221. "arrays with scalar values instead. The filled function "
  3222. "still supports any array as `fill_value`.",
  3223. DeprecationWarning, stacklevel=2)
  3224. _fill_value = self._fill_value
  3225. if _fill_value is None:
  3226. # Create the attribute if it was undefined
  3227. self._fill_value = target
  3228. else:
  3229. # Don't overwrite the attribute, just fill it (for propagation)
  3230. _fill_value[()] = target
  3231. # kept for compatibility
  3232. get_fill_value = fill_value.fget
  3233. set_fill_value = fill_value.fset
  3234. def filled(self, fill_value=None):
  3235. """
  3236. Return a copy of self, with masked values filled with a given value.
  3237. **However**, if there are no masked values to fill, self will be
  3238. returned instead as an ndarray.
  3239. Parameters
  3240. ----------
  3241. fill_value : array_like, optional
  3242. The value to use for invalid entries. Can be scalar or non-scalar.
  3243. If non-scalar, the resulting ndarray must be broadcastable over
  3244. input array. Default is None, in which case, the `fill_value`
  3245. attribute of the array is used instead.
  3246. Returns
  3247. -------
  3248. filled_array : ndarray
  3249. A copy of ``self`` with invalid entries replaced by *fill_value*
  3250. (be it the function argument or the attribute of ``self``), or
  3251. ``self`` itself as an ndarray if there are no invalid entries to
  3252. be replaced.
  3253. Notes
  3254. -----
  3255. The result is **not** a MaskedArray!
  3256. Examples
  3257. --------
  3258. >>> import numpy as np
  3259. >>> x = np.ma.array([1,2,3,4,5], mask=[0,0,1,0,1], fill_value=-999)
  3260. >>> x.filled()
  3261. array([ 1, 2, -999, 4, -999])
  3262. >>> x.filled(fill_value=1000)
  3263. array([ 1, 2, 1000, 4, 1000])
  3264. >>> type(x.filled())
  3265. <class 'numpy.ndarray'>
  3266. Subclassing is preserved. This means that if, e.g., the data part of
  3267. the masked array is a recarray, `filled` returns a recarray:
  3268. >>> x = np.array([(-1, 2), (-3, 4)], dtype='i8,i8').view(np.recarray)
  3269. >>> m = np.ma.array(x, mask=[(True, False), (False, True)])
  3270. >>> m.filled()
  3271. rec.array([(999999, 2), ( -3, 999999)],
  3272. dtype=[('f0', '<i8'), ('f1', '<i8')])
  3273. """
  3274. m = self._mask
  3275. if m is nomask:
  3276. return self._data
  3277. if fill_value is None:
  3278. fill_value = self.fill_value
  3279. else:
  3280. fill_value = _check_fill_value(fill_value, self.dtype)
  3281. if self is masked_singleton:
  3282. return np.asanyarray(fill_value)
  3283. if m.dtype.names is not None:
  3284. result = self._data.copy('K')
  3285. _recursive_filled(result, self._mask, fill_value)
  3286. elif not m.any():
  3287. return self._data
  3288. else:
  3289. result = self._data.copy('K')
  3290. try:
  3291. np.copyto(result, fill_value, where=m)
  3292. except (TypeError, AttributeError):
  3293. fill_value = narray(fill_value, dtype=object)
  3294. d = result.astype(object)
  3295. result = np.choose(m, (d, fill_value))
  3296. except IndexError:
  3297. # ok, if scalar
  3298. if self._data.shape:
  3299. raise
  3300. elif m:
  3301. result = np.array(fill_value, dtype=self.dtype)
  3302. else:
  3303. result = self._data
  3304. return result
  3305. def compressed(self):
  3306. """
  3307. Return all the non-masked data as a 1-D array.
  3308. Returns
  3309. -------
  3310. data : ndarray
  3311. A new `ndarray` holding the non-masked data is returned.
  3312. Notes
  3313. -----
  3314. The result is **not** a MaskedArray!
  3315. Examples
  3316. --------
  3317. >>> import numpy as np
  3318. >>> x = np.ma.array(np.arange(5), mask=[0]*2 + [1]*3)
  3319. >>> x.compressed()
  3320. array([0, 1])
  3321. >>> type(x.compressed())
  3322. <class 'numpy.ndarray'>
  3323. N-D arrays are compressed to 1-D.
  3324. >>> arr = [[1, 2], [3, 4]]
  3325. >>> mask = [[1, 0], [0, 1]]
  3326. >>> x = np.ma.array(arr, mask=mask)
  3327. >>> x.compressed()
  3328. array([2, 3])
  3329. """
  3330. data = ndarray.ravel(self._data)
  3331. if self._mask is not nomask:
  3332. data = data.compress(np.logical_not(ndarray.ravel(self._mask)))
  3333. return data
  3334. def compress(self, condition, axis=None, out=None):
  3335. """
  3336. Return `a` where condition is ``True``.
  3337. If condition is a `~ma.MaskedArray`, missing values are considered
  3338. as ``False``.
  3339. Parameters
  3340. ----------
  3341. condition : var
  3342. Boolean 1-d array selecting which entries to return. If len(condition)
  3343. is less than the size of a along the axis, then output is truncated
  3344. to length of condition array.
  3345. axis : {None, int}, optional
  3346. Axis along which the operation must be performed.
  3347. out : {None, ndarray}, optional
  3348. Alternative output array in which to place the result. It must have
  3349. the same shape as the expected output but the type will be cast if
  3350. necessary.
  3351. Returns
  3352. -------
  3353. result : MaskedArray
  3354. A :class:`~ma.MaskedArray` object.
  3355. Notes
  3356. -----
  3357. Please note the difference with :meth:`compressed` !
  3358. The output of :meth:`compress` has a mask, the output of
  3359. :meth:`compressed` does not.
  3360. Examples
  3361. --------
  3362. >>> import numpy as np
  3363. >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4)
  3364. >>> x
  3365. masked_array(
  3366. data=[[1, --, 3],
  3367. [--, 5, --],
  3368. [7, --, 9]],
  3369. mask=[[False, True, False],
  3370. [ True, False, True],
  3371. [False, True, False]],
  3372. fill_value=999999)
  3373. >>> x.compress([1, 0, 1])
  3374. masked_array(data=[1, 3],
  3375. mask=[False, False],
  3376. fill_value=999999)
  3377. >>> x.compress([1, 0, 1], axis=1)
  3378. masked_array(
  3379. data=[[1, 3],
  3380. [--, --],
  3381. [7, 9]],
  3382. mask=[[False, False],
  3383. [ True, True],
  3384. [False, False]],
  3385. fill_value=999999)
  3386. """
  3387. # Get the basic components
  3388. (_data, _mask) = (self._data, self._mask)
  3389. # Force the condition to a regular ndarray and forget the missing
  3390. # values.
  3391. condition = np.asarray(condition)
  3392. _new = _data.compress(condition, axis=axis, out=out).view(type(self))
  3393. _new._update_from(self)
  3394. if _mask is not nomask:
  3395. _new._mask = _mask.compress(condition, axis=axis)
  3396. return _new
  3397. def _insert_masked_print(self):
  3398. """
  3399. Replace masked values with masked_print_option, casting all innermost
  3400. dtypes to object.
  3401. """
  3402. if masked_print_option.enabled():
  3403. mask = self._mask
  3404. if mask is nomask:
  3405. res = self._data
  3406. else:
  3407. # convert to object array to make filled work
  3408. data = self._data
  3409. # For big arrays, to avoid a costly conversion to the
  3410. # object dtype, extract the corners before the conversion.
  3411. print_width = (self._print_width if self.ndim > 1
  3412. else self._print_width_1d)
  3413. for axis in range(self.ndim):
  3414. if data.shape[axis] > print_width:
  3415. ind = print_width // 2
  3416. arr = np.split(data, (ind, -ind), axis=axis)
  3417. data = np.concatenate((arr[0], arr[2]), axis=axis)
  3418. arr = np.split(mask, (ind, -ind), axis=axis)
  3419. mask = np.concatenate((arr[0], arr[2]), axis=axis)
  3420. rdtype = _replace_dtype_fields(self.dtype, "O")
  3421. res = data.astype(rdtype)
  3422. _recursive_printoption(res, mask, masked_print_option)
  3423. else:
  3424. res = self.filled(self.fill_value)
  3425. return res
  3426. def __str__(self):
  3427. return str(self._insert_masked_print())
  3428. def __repr__(self):
  3429. """
  3430. Literal string representation.
  3431. """
  3432. if self._baseclass is np.ndarray:
  3433. name = 'array'
  3434. else:
  3435. name = self._baseclass.__name__
  3436. # 2016-11-19: Demoted to legacy format
  3437. if np._core.arrayprint._get_legacy_print_mode() <= 113:
  3438. is_long = self.ndim > 1
  3439. parameters = dict(
  3440. name=name,
  3441. nlen=" " * len(name),
  3442. data=str(self),
  3443. mask=str(self._mask),
  3444. fill=str(self.fill_value),
  3445. dtype=str(self.dtype)
  3446. )
  3447. is_structured = bool(self.dtype.names)
  3448. key = '{}_{}'.format(
  3449. 'long' if is_long else 'short',
  3450. 'flx' if is_structured else 'std'
  3451. )
  3452. return _legacy_print_templates[key] % parameters
  3453. prefix = f"masked_{name}("
  3454. dtype_needed = (
  3455. not np._core.arrayprint.dtype_is_implied(self.dtype) or
  3456. np.all(self.mask) or
  3457. self.size == 0
  3458. )
  3459. # determine which keyword args need to be shown
  3460. keys = ['data', 'mask', 'fill_value']
  3461. if dtype_needed:
  3462. keys.append('dtype')
  3463. # array has only one row (non-column)
  3464. is_one_row = builtins.all(dim == 1 for dim in self.shape[:-1])
  3465. # choose what to indent each keyword with
  3466. min_indent = 2
  3467. if is_one_row:
  3468. # first key on the same line as the type, remaining keys
  3469. # aligned by equals
  3470. indents = {}
  3471. indents[keys[0]] = prefix
  3472. for k in keys[1:]:
  3473. n = builtins.max(min_indent, len(prefix + keys[0]) - len(k))
  3474. indents[k] = ' ' * n
  3475. prefix = '' # absorbed into the first indent
  3476. else:
  3477. # each key on its own line, indented by two spaces
  3478. indents = {k: ' ' * min_indent for k in keys}
  3479. prefix = prefix + '\n' # first key on the next line
  3480. # format the field values
  3481. reprs = {}
  3482. reprs['data'] = np.array2string(
  3483. self._insert_masked_print(),
  3484. separator=", ",
  3485. prefix=indents['data'] + 'data=',
  3486. suffix=',')
  3487. reprs['mask'] = np.array2string(
  3488. self._mask,
  3489. separator=", ",
  3490. prefix=indents['mask'] + 'mask=',
  3491. suffix=',')
  3492. if self._fill_value is None:
  3493. self.fill_value # initialize fill_value
  3494. if (self._fill_value.dtype.kind in ("S", "U")
  3495. and self.dtype.kind == self._fill_value.dtype.kind):
  3496. # Allow strings: "N/A" has length 3 so would mismatch.
  3497. fill_repr = repr(self.fill_value.item())
  3498. elif self._fill_value.dtype == self.dtype and not self.dtype == object:
  3499. # Guess that it is OK to use the string as item repr. To really
  3500. # fix this, it needs new logic (shared with structured scalars)
  3501. fill_repr = str(self.fill_value)
  3502. else:
  3503. fill_repr = repr(self.fill_value)
  3504. reprs['fill_value'] = fill_repr
  3505. if dtype_needed:
  3506. reprs['dtype'] = np._core.arrayprint.dtype_short_repr(self.dtype)
  3507. # join keys with values and indentations
  3508. result = ',\n'.join(
  3509. '{}{}={}'.format(indents[k], k, reprs[k])
  3510. for k in keys
  3511. )
  3512. return prefix + result + ')'
  3513. def _delegate_binop(self, other):
  3514. # This emulates the logic in
  3515. # private/binop_override.h:forward_binop_should_defer
  3516. if isinstance(other, type(self)):
  3517. return False
  3518. array_ufunc = getattr(other, "__array_ufunc__", False)
  3519. if array_ufunc is False:
  3520. other_priority = getattr(other, "__array_priority__", -1000000)
  3521. return self.__array_priority__ < other_priority
  3522. else:
  3523. # If array_ufunc is not None, it will be called inside the ufunc;
  3524. # None explicitly tells us to not call the ufunc, i.e., defer.
  3525. return array_ufunc is None
  3526. def _comparison(self, other, compare):
  3527. """Compare self with other using operator.eq or operator.ne.
  3528. When either of the elements is masked, the result is masked as well,
  3529. but the underlying boolean data are still set, with self and other
  3530. considered equal if both are masked, and unequal otherwise.
  3531. For structured arrays, all fields are combined, with masked values
  3532. ignored. The result is masked if all fields were masked, with self
  3533. and other considered equal only if both were fully masked.
  3534. """
  3535. omask = getmask(other)
  3536. smask = self.mask
  3537. mask = mask_or(smask, omask, copy=True)
  3538. odata = getdata(other)
  3539. if mask.dtype.names is not None:
  3540. # only == and != are reasonably defined for structured dtypes,
  3541. # so give up early for all other comparisons:
  3542. if compare not in (operator.eq, operator.ne):
  3543. return NotImplemented
  3544. # For possibly masked structured arrays we need to be careful,
  3545. # since the standard structured array comparison will use all
  3546. # fields, masked or not. To avoid masked fields influencing the
  3547. # outcome, we set all masked fields in self to other, so they'll
  3548. # count as equal. To prepare, we ensure we have the right shape.
  3549. broadcast_shape = np.broadcast(self, odata).shape
  3550. sbroadcast = np.broadcast_to(self, broadcast_shape, subok=True)
  3551. sbroadcast._mask = mask
  3552. sdata = sbroadcast.filled(odata)
  3553. # Now take care of the mask; the merged mask should have an item
  3554. # masked if all fields were masked (in one and/or other).
  3555. mask = (mask == np.ones((), mask.dtype))
  3556. # Ensure we can compare masks below if other was not masked.
  3557. if omask is np.False_:
  3558. omask = np.zeros((), smask.dtype)
  3559. else:
  3560. # For regular arrays, just use the data as they come.
  3561. sdata = self.data
  3562. check = compare(sdata, odata)
  3563. if isinstance(check, (np.bool, bool)):
  3564. return masked if mask else check
  3565. if mask is not nomask:
  3566. if compare in (operator.eq, operator.ne):
  3567. # Adjust elements that were masked, which should be treated
  3568. # as equal if masked in both, unequal if masked in one.
  3569. # Note that this works automatically for structured arrays too.
  3570. # Ignore this for operations other than `==` and `!=`
  3571. check = np.where(mask, compare(smask, omask), check)
  3572. if mask.shape != check.shape:
  3573. # Guarantee consistency of the shape, making a copy since the
  3574. # the mask may need to get written to later.
  3575. mask = np.broadcast_to(mask, check.shape).copy()
  3576. check = check.view(type(self))
  3577. check._update_from(self)
  3578. check._mask = mask
  3579. # Cast fill value to np.bool if needed. If it cannot be cast, the
  3580. # default boolean fill value is used.
  3581. if check._fill_value is not None:
  3582. try:
  3583. fill = _check_fill_value(check._fill_value, np.bool)
  3584. except (TypeError, ValueError):
  3585. fill = _check_fill_value(None, np.bool)
  3586. check._fill_value = fill
  3587. return check
  3588. def __eq__(self, other):
  3589. """Check whether other equals self elementwise.
  3590. When either of the elements is masked, the result is masked as well,
  3591. but the underlying boolean data are still set, with self and other
  3592. considered equal if both are masked, and unequal otherwise.
  3593. For structured arrays, all fields are combined, with masked values
  3594. ignored. The result is masked if all fields were masked, with self
  3595. and other considered equal only if both were fully masked.
  3596. """
  3597. return self._comparison(other, operator.eq)
  3598. def __ne__(self, other):
  3599. """Check whether other does not equal self elementwise.
  3600. When either of the elements is masked, the result is masked as well,
  3601. but the underlying boolean data are still set, with self and other
  3602. considered equal if both are masked, and unequal otherwise.
  3603. For structured arrays, all fields are combined, with masked values
  3604. ignored. The result is masked if all fields were masked, with self
  3605. and other considered equal only if both were fully masked.
  3606. """
  3607. return self._comparison(other, operator.ne)
  3608. # All other comparisons:
  3609. def __le__(self, other):
  3610. return self._comparison(other, operator.le)
  3611. def __lt__(self, other):
  3612. return self._comparison(other, operator.lt)
  3613. def __ge__(self, other):
  3614. return self._comparison(other, operator.ge)
  3615. def __gt__(self, other):
  3616. return self._comparison(other, operator.gt)
  3617. def __add__(self, other):
  3618. """
  3619. Add self to other, and return a new masked array.
  3620. """
  3621. if self._delegate_binop(other):
  3622. return NotImplemented
  3623. return add(self, other)
  3624. def __radd__(self, other):
  3625. """
  3626. Add other to self, and return a new masked array.
  3627. """
  3628. # In analogy with __rsub__ and __rdiv__, use original order:
  3629. # we get here from `other + self`.
  3630. return add(other, self)
  3631. def __sub__(self, other):
  3632. """
  3633. Subtract other from self, and return a new masked array.
  3634. """
  3635. if self._delegate_binop(other):
  3636. return NotImplemented
  3637. return subtract(self, other)
  3638. def __rsub__(self, other):
  3639. """
  3640. Subtract self from other, and return a new masked array.
  3641. """
  3642. return subtract(other, self)
  3643. def __mul__(self, other):
  3644. "Multiply self by other, and return a new masked array."
  3645. if self._delegate_binop(other):
  3646. return NotImplemented
  3647. return multiply(self, other)
  3648. def __rmul__(self, other):
  3649. """
  3650. Multiply other by self, and return a new masked array.
  3651. """
  3652. # In analogy with __rsub__ and __rdiv__, use original order:
  3653. # we get here from `other * self`.
  3654. return multiply(other, self)
  3655. def __div__(self, other):
  3656. """
  3657. Divide other into self, and return a new masked array.
  3658. """
  3659. if self._delegate_binop(other):
  3660. return NotImplemented
  3661. return divide(self, other)
  3662. def __truediv__(self, other):
  3663. """
  3664. Divide other into self, and return a new masked array.
  3665. """
  3666. if self._delegate_binop(other):
  3667. return NotImplemented
  3668. return true_divide(self, other)
  3669. def __rtruediv__(self, other):
  3670. """
  3671. Divide self into other, and return a new masked array.
  3672. """
  3673. return true_divide(other, self)
  3674. def __floordiv__(self, other):
  3675. """
  3676. Divide other into self, and return a new masked array.
  3677. """
  3678. if self._delegate_binop(other):
  3679. return NotImplemented
  3680. return floor_divide(self, other)
  3681. def __rfloordiv__(self, other):
  3682. """
  3683. Divide self into other, and return a new masked array.
  3684. """
  3685. return floor_divide(other, self)
  3686. def __pow__(self, other):
  3687. """
  3688. Raise self to the power other, masking the potential NaNs/Infs
  3689. """
  3690. if self._delegate_binop(other):
  3691. return NotImplemented
  3692. return power(self, other)
  3693. def __rpow__(self, other):
  3694. """
  3695. Raise other to the power self, masking the potential NaNs/Infs
  3696. """
  3697. return power(other, self)
  3698. def __iadd__(self, other):
  3699. """
  3700. Add other to self in-place.
  3701. """
  3702. m = getmask(other)
  3703. if self._mask is nomask:
  3704. if m is not nomask and m.any():
  3705. self._mask = make_mask_none(self.shape, self.dtype)
  3706. self._mask += m
  3707. else:
  3708. if m is not nomask:
  3709. self._mask += m
  3710. other_data = getdata(other)
  3711. other_data = np.where(self._mask, other_data.dtype.type(0), other_data)
  3712. self._data.__iadd__(other_data)
  3713. return self
  3714. def __isub__(self, other):
  3715. """
  3716. Subtract other from self in-place.
  3717. """
  3718. m = getmask(other)
  3719. if self._mask is nomask:
  3720. if m is not nomask and m.any():
  3721. self._mask = make_mask_none(self.shape, self.dtype)
  3722. self._mask += m
  3723. elif m is not nomask:
  3724. self._mask += m
  3725. other_data = getdata(other)
  3726. other_data = np.where(self._mask, other_data.dtype.type(0), other_data)
  3727. self._data.__isub__(other_data)
  3728. return self
  3729. def __imul__(self, other):
  3730. """
  3731. Multiply self by other in-place.
  3732. """
  3733. m = getmask(other)
  3734. if self._mask is nomask:
  3735. if m is not nomask and m.any():
  3736. self._mask = make_mask_none(self.shape, self.dtype)
  3737. self._mask += m
  3738. elif m is not nomask:
  3739. self._mask += m
  3740. other_data = getdata(other)
  3741. other_data = np.where(self._mask, other_data.dtype.type(1), other_data)
  3742. self._data.__imul__(other_data)
  3743. return self
  3744. def __idiv__(self, other):
  3745. """
  3746. Divide self by other in-place.
  3747. """
  3748. other_data = getdata(other)
  3749. dom_mask = _DomainSafeDivide().__call__(self._data, other_data)
  3750. other_mask = getmask(other)
  3751. new_mask = mask_or(other_mask, dom_mask)
  3752. # The following 4 lines control the domain filling
  3753. if dom_mask.any():
  3754. (_, fval) = ufunc_fills[np.divide]
  3755. other_data = np.where(
  3756. dom_mask, other_data.dtype.type(fval), other_data)
  3757. self._mask |= new_mask
  3758. other_data = np.where(self._mask, other_data.dtype.type(1), other_data)
  3759. self._data.__idiv__(other_data)
  3760. return self
  3761. def __ifloordiv__(self, other):
  3762. """
  3763. Floor divide self by other in-place.
  3764. """
  3765. other_data = getdata(other)
  3766. dom_mask = _DomainSafeDivide().__call__(self._data, other_data)
  3767. other_mask = getmask(other)
  3768. new_mask = mask_or(other_mask, dom_mask)
  3769. # The following 3 lines control the domain filling
  3770. if dom_mask.any():
  3771. (_, fval) = ufunc_fills[np.floor_divide]
  3772. other_data = np.where(
  3773. dom_mask, other_data.dtype.type(fval), other_data)
  3774. self._mask |= new_mask
  3775. other_data = np.where(self._mask, other_data.dtype.type(1), other_data)
  3776. self._data.__ifloordiv__(other_data)
  3777. return self
  3778. def __itruediv__(self, other):
  3779. """
  3780. True divide self by other in-place.
  3781. """
  3782. other_data = getdata(other)
  3783. dom_mask = _DomainSafeDivide().__call__(self._data, other_data)
  3784. other_mask = getmask(other)
  3785. new_mask = mask_or(other_mask, dom_mask)
  3786. # The following 3 lines control the domain filling
  3787. if dom_mask.any():
  3788. (_, fval) = ufunc_fills[np.true_divide]
  3789. other_data = np.where(
  3790. dom_mask, other_data.dtype.type(fval), other_data)
  3791. self._mask |= new_mask
  3792. other_data = np.where(self._mask, other_data.dtype.type(1), other_data)
  3793. self._data.__itruediv__(other_data)
  3794. return self
  3795. def __ipow__(self, other):
  3796. """
  3797. Raise self to the power other, in place.
  3798. """
  3799. other_data = getdata(other)
  3800. other_data = np.where(self._mask, other_data.dtype.type(1), other_data)
  3801. other_mask = getmask(other)
  3802. with np.errstate(divide='ignore', invalid='ignore'):
  3803. self._data.__ipow__(other_data)
  3804. invalid = np.logical_not(np.isfinite(self._data))
  3805. if invalid.any():
  3806. if self._mask is not nomask:
  3807. self._mask |= invalid
  3808. else:
  3809. self._mask = invalid
  3810. np.copyto(self._data, self.fill_value, where=invalid)
  3811. new_mask = mask_or(other_mask, invalid)
  3812. self._mask = mask_or(self._mask, new_mask)
  3813. return self
  3814. def __float__(self):
  3815. """
  3816. Convert to float.
  3817. """
  3818. if self.size > 1:
  3819. raise TypeError("Only length-1 arrays can be converted "
  3820. "to Python scalars")
  3821. elif self._mask:
  3822. warnings.warn("Warning: converting a masked element to nan.", stacklevel=2)
  3823. return np.nan
  3824. return float(self.item())
  3825. def __int__(self):
  3826. """
  3827. Convert to int.
  3828. """
  3829. if self.size > 1:
  3830. raise TypeError("Only length-1 arrays can be converted "
  3831. "to Python scalars")
  3832. elif self._mask:
  3833. raise MaskError('Cannot convert masked element to a Python int.')
  3834. return int(self.item())
  3835. @property
  3836. def imag(self):
  3837. """
  3838. The imaginary part of the masked array.
  3839. This property is a view on the imaginary part of this `MaskedArray`.
  3840. See Also
  3841. --------
  3842. real
  3843. Examples
  3844. --------
  3845. >>> import numpy as np
  3846. >>> x = np.ma.array([1+1.j, -2j, 3.45+1.6j], mask=[False, True, False])
  3847. >>> x.imag
  3848. masked_array(data=[1.0, --, 1.6],
  3849. mask=[False, True, False],
  3850. fill_value=1e+20)
  3851. """
  3852. result = self._data.imag.view(type(self))
  3853. result.__setmask__(self._mask)
  3854. return result
  3855. # kept for compatibility
  3856. get_imag = imag.fget
  3857. @property
  3858. def real(self):
  3859. """
  3860. The real part of the masked array.
  3861. This property is a view on the real part of this `MaskedArray`.
  3862. See Also
  3863. --------
  3864. imag
  3865. Examples
  3866. --------
  3867. >>> import numpy as np
  3868. >>> x = np.ma.array([1+1.j, -2j, 3.45+1.6j], mask=[False, True, False])
  3869. >>> x.real
  3870. masked_array(data=[1.0, --, 3.45],
  3871. mask=[False, True, False],
  3872. fill_value=1e+20)
  3873. """
  3874. result = self._data.real.view(type(self))
  3875. result.__setmask__(self._mask)
  3876. return result
  3877. # kept for compatibility
  3878. get_real = real.fget
  3879. def count(self, axis=None, keepdims=np._NoValue):
  3880. """
  3881. Count the non-masked elements of the array along the given axis.
  3882. Parameters
  3883. ----------
  3884. axis : None or int or tuple of ints, optional
  3885. Axis or axes along which the count is performed.
  3886. The default, None, performs the count over all
  3887. the dimensions of the input array. `axis` may be negative, in
  3888. which case it counts from the last to the first axis.
  3889. If this is a tuple of ints, the count is performed on multiple
  3890. axes, instead of a single axis or all the axes as before.
  3891. keepdims : bool, optional
  3892. If this is set to True, the axes which are reduced are left
  3893. in the result as dimensions with size one. With this option,
  3894. the result will broadcast correctly against the array.
  3895. Returns
  3896. -------
  3897. result : ndarray or scalar
  3898. An array with the same shape as the input array, with the specified
  3899. axis removed. If the array is a 0-d array, or if `axis` is None, a
  3900. scalar is returned.
  3901. See Also
  3902. --------
  3903. ma.count_masked : Count masked elements in array or along a given axis.
  3904. Examples
  3905. --------
  3906. >>> import numpy.ma as ma
  3907. >>> a = ma.arange(6).reshape((2, 3))
  3908. >>> a[1, :] = ma.masked
  3909. >>> a
  3910. masked_array(
  3911. data=[[0, 1, 2],
  3912. [--, --, --]],
  3913. mask=[[False, False, False],
  3914. [ True, True, True]],
  3915. fill_value=999999)
  3916. >>> a.count()
  3917. 3
  3918. When the `axis` keyword is specified an array of appropriate size is
  3919. returned.
  3920. >>> a.count(axis=0)
  3921. array([1, 1, 1])
  3922. >>> a.count(axis=1)
  3923. array([3, 0])
  3924. """
  3925. kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
  3926. m = self._mask
  3927. # special case for matrices (we assume no other subclasses modify
  3928. # their dimensions)
  3929. if isinstance(self.data, np.matrix):
  3930. if m is nomask:
  3931. m = np.zeros(self.shape, dtype=np.bool)
  3932. m = m.view(type(self.data))
  3933. if m is nomask:
  3934. # compare to _count_reduce_items in _methods.py
  3935. if self.shape == ():
  3936. if axis not in (None, 0):
  3937. raise np.exceptions.AxisError(axis=axis, ndim=self.ndim)
  3938. return 1
  3939. elif axis is None:
  3940. if kwargs.get('keepdims', False):
  3941. return np.array(self.size, dtype=np.intp, ndmin=self.ndim)
  3942. return self.size
  3943. axes = normalize_axis_tuple(axis, self.ndim)
  3944. items = 1
  3945. for ax in axes:
  3946. items *= self.shape[ax]
  3947. if kwargs.get('keepdims', False):
  3948. out_dims = list(self.shape)
  3949. for a in axes:
  3950. out_dims[a] = 1
  3951. else:
  3952. out_dims = [d for n, d in enumerate(self.shape)
  3953. if n not in axes]
  3954. # make sure to return a 0-d array if axis is supplied
  3955. return np.full(out_dims, items, dtype=np.intp)
  3956. # take care of the masked singleton
  3957. if self is masked:
  3958. return 0
  3959. return (~m).sum(axis=axis, dtype=np.intp, **kwargs)
  3960. def ravel(self, order='C'):
  3961. """
  3962. Returns a 1D version of self, as a view.
  3963. Parameters
  3964. ----------
  3965. order : {'C', 'F', 'A', 'K'}, optional
  3966. The elements of `a` are read using this index order. 'C' means to
  3967. index the elements in C-like order, with the last axis index
  3968. changing fastest, back to the first axis index changing slowest.
  3969. 'F' means to index the elements in Fortran-like index order, with
  3970. the first index changing fastest, and the last index changing
  3971. slowest. Note that the 'C' and 'F' options take no account of the
  3972. memory layout of the underlying array, and only refer to the order
  3973. of axis indexing. 'A' means to read the elements in Fortran-like
  3974. index order if `m` is Fortran *contiguous* in memory, C-like order
  3975. otherwise. 'K' means to read the elements in the order they occur
  3976. in memory, except for reversing the data when strides are negative.
  3977. By default, 'C' index order is used.
  3978. (Masked arrays currently use 'A' on the data when 'K' is passed.)
  3979. Returns
  3980. -------
  3981. MaskedArray
  3982. Output view is of shape ``(self.size,)`` (or
  3983. ``(np.ma.product(self.shape),)``).
  3984. Examples
  3985. --------
  3986. >>> import numpy as np
  3987. >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4)
  3988. >>> x
  3989. masked_array(
  3990. data=[[1, --, 3],
  3991. [--, 5, --],
  3992. [7, --, 9]],
  3993. mask=[[False, True, False],
  3994. [ True, False, True],
  3995. [False, True, False]],
  3996. fill_value=999999)
  3997. >>> x.ravel()
  3998. masked_array(data=[1, --, 3, --, 5, --, 7, --, 9],
  3999. mask=[False, True, False, True, False, True, False, True,
  4000. False],
  4001. fill_value=999999)
  4002. """
  4003. # The order of _data and _mask could be different (it shouldn't be
  4004. # normally). Passing order `K` or `A` would be incorrect.
  4005. # So we ignore the mask memory order.
  4006. # TODO: We don't actually support K, so use A instead. We could
  4007. # try to guess this correct by sorting strides or deprecate.
  4008. if order in "kKaA":
  4009. order = "F" if self._data.flags.fnc else "C"
  4010. r = ndarray.ravel(self._data, order=order).view(type(self))
  4011. r._update_from(self)
  4012. if self._mask is not nomask:
  4013. r._mask = ndarray.ravel(self._mask, order=order).reshape(r.shape)
  4014. else:
  4015. r._mask = nomask
  4016. return r
  4017. def reshape(self, *s, **kwargs):
  4018. """
  4019. Give a new shape to the array without changing its data.
  4020. Returns a masked array containing the same data, but with a new shape.
  4021. The result is a view on the original array; if this is not possible, a
  4022. ValueError is raised.
  4023. Parameters
  4024. ----------
  4025. shape : int or tuple of ints
  4026. The new shape should be compatible with the original shape. If an
  4027. integer is supplied, then the result will be a 1-D array of that
  4028. length.
  4029. order : {'C', 'F'}, optional
  4030. Determines whether the array data should be viewed as in C
  4031. (row-major) or FORTRAN (column-major) order.
  4032. Returns
  4033. -------
  4034. reshaped_array : array
  4035. A new view on the array.
  4036. See Also
  4037. --------
  4038. reshape : Equivalent function in the masked array module.
  4039. numpy.ndarray.reshape : Equivalent method on ndarray object.
  4040. numpy.reshape : Equivalent function in the NumPy module.
  4041. Notes
  4042. -----
  4043. The reshaping operation cannot guarantee that a copy will not be made,
  4044. to modify the shape in place, use ``a.shape = s``
  4045. Examples
  4046. --------
  4047. >>> import numpy as np
  4048. >>> x = np.ma.array([[1,2],[3,4]], mask=[1,0,0,1])
  4049. >>> x
  4050. masked_array(
  4051. data=[[--, 2],
  4052. [3, --]],
  4053. mask=[[ True, False],
  4054. [False, True]],
  4055. fill_value=999999)
  4056. >>> x = x.reshape((4,1))
  4057. >>> x
  4058. masked_array(
  4059. data=[[--],
  4060. [2],
  4061. [3],
  4062. [--]],
  4063. mask=[[ True],
  4064. [False],
  4065. [False],
  4066. [ True]],
  4067. fill_value=999999)
  4068. """
  4069. kwargs.update(order=kwargs.get('order', 'C'))
  4070. result = self._data.reshape(*s, **kwargs).view(type(self))
  4071. result._update_from(self)
  4072. mask = self._mask
  4073. if mask is not nomask:
  4074. result._mask = mask.reshape(*s, **kwargs)
  4075. return result
  4076. def resize(self, newshape, refcheck=True, order=False):
  4077. """
  4078. .. warning::
  4079. This method does nothing, except raise a ValueError exception. A
  4080. masked array does not own its data and therefore cannot safely be
  4081. resized in place. Use the `numpy.ma.resize` function instead.
  4082. This method is difficult to implement safely and may be deprecated in
  4083. future releases of NumPy.
  4084. """
  4085. # Note : the 'order' keyword looks broken, let's just drop it
  4086. errmsg = "A masked array does not own its data "\
  4087. "and therefore cannot be resized.\n" \
  4088. "Use the numpy.ma.resize function instead."
  4089. raise ValueError(errmsg)
  4090. def put(self, indices, values, mode='raise'):
  4091. """
  4092. Set storage-indexed locations to corresponding values.
  4093. Sets self._data.flat[n] = values[n] for each n in indices.
  4094. If `values` is shorter than `indices` then it will repeat.
  4095. If `values` has some masked values, the initial mask is updated
  4096. in consequence, else the corresponding values are unmasked.
  4097. Parameters
  4098. ----------
  4099. indices : 1-D array_like
  4100. Target indices, interpreted as integers.
  4101. values : array_like
  4102. Values to place in self._data copy at target indices.
  4103. mode : {'raise', 'wrap', 'clip'}, optional
  4104. Specifies how out-of-bounds indices will behave.
  4105. 'raise' : raise an error.
  4106. 'wrap' : wrap around.
  4107. 'clip' : clip to the range.
  4108. Notes
  4109. -----
  4110. `values` can be a scalar or length 1 array.
  4111. Examples
  4112. --------
  4113. >>> import numpy as np
  4114. >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4)
  4115. >>> x
  4116. masked_array(
  4117. data=[[1, --, 3],
  4118. [--, 5, --],
  4119. [7, --, 9]],
  4120. mask=[[False, True, False],
  4121. [ True, False, True],
  4122. [False, True, False]],
  4123. fill_value=999999)
  4124. >>> x.put([0,4,8],[10,20,30])
  4125. >>> x
  4126. masked_array(
  4127. data=[[10, --, 3],
  4128. [--, 20, --],
  4129. [7, --, 30]],
  4130. mask=[[False, True, False],
  4131. [ True, False, True],
  4132. [False, True, False]],
  4133. fill_value=999999)
  4134. >>> x.put(4,999)
  4135. >>> x
  4136. masked_array(
  4137. data=[[10, --, 3],
  4138. [--, 999, --],
  4139. [7, --, 30]],
  4140. mask=[[False, True, False],
  4141. [ True, False, True],
  4142. [False, True, False]],
  4143. fill_value=999999)
  4144. """
  4145. # Hard mask: Get rid of the values/indices that fall on masked data
  4146. if self._hardmask and self._mask is not nomask:
  4147. mask = self._mask[indices]
  4148. indices = narray(indices, copy=None)
  4149. values = narray(values, copy=None, subok=True)
  4150. values.resize(indices.shape)
  4151. indices = indices[~mask]
  4152. values = values[~mask]
  4153. self._data.put(indices, values, mode=mode)
  4154. # short circuit if neither self nor values are masked
  4155. if self._mask is nomask and getmask(values) is nomask:
  4156. return
  4157. m = getmaskarray(self)
  4158. if getmask(values) is nomask:
  4159. m.put(indices, False, mode=mode)
  4160. else:
  4161. m.put(indices, values._mask, mode=mode)
  4162. m = make_mask(m, copy=False, shrink=True)
  4163. self._mask = m
  4164. return
  4165. def ids(self):
  4166. """
  4167. Return the addresses of the data and mask areas.
  4168. Parameters
  4169. ----------
  4170. None
  4171. Examples
  4172. --------
  4173. >>> import numpy as np
  4174. >>> x = np.ma.array([1, 2, 3], mask=[0, 1, 1])
  4175. >>> x.ids()
  4176. (166670640, 166659832) # may vary
  4177. If the array has no mask, the address of `nomask` is returned. This address
  4178. is typically not close to the data in memory:
  4179. >>> x = np.ma.array([1, 2, 3])
  4180. >>> x.ids()
  4181. (166691080, 3083169284) # may vary
  4182. """
  4183. if self._mask is nomask:
  4184. return (self.ctypes.data, id(nomask))
  4185. return (self.ctypes.data, self._mask.ctypes.data)
  4186. def iscontiguous(self):
  4187. """
  4188. Return a boolean indicating whether the data is contiguous.
  4189. Parameters
  4190. ----------
  4191. None
  4192. Examples
  4193. --------
  4194. >>> import numpy as np
  4195. >>> x = np.ma.array([1, 2, 3])
  4196. >>> x.iscontiguous()
  4197. True
  4198. `iscontiguous` returns one of the flags of the masked array:
  4199. >>> x.flags
  4200. C_CONTIGUOUS : True
  4201. F_CONTIGUOUS : True
  4202. OWNDATA : False
  4203. WRITEABLE : True
  4204. ALIGNED : True
  4205. WRITEBACKIFCOPY : False
  4206. """
  4207. return self.flags['CONTIGUOUS']
  4208. def all(self, axis=None, out=None, keepdims=np._NoValue):
  4209. """
  4210. Returns True if all elements evaluate to True.
  4211. The output array is masked where all the values along the given axis
  4212. are masked: if the output would have been a scalar and that all the
  4213. values are masked, then the output is `masked`.
  4214. Refer to `numpy.all` for full documentation.
  4215. See Also
  4216. --------
  4217. numpy.ndarray.all : corresponding function for ndarrays
  4218. numpy.all : equivalent function
  4219. Examples
  4220. --------
  4221. >>> import numpy as np
  4222. >>> np.ma.array([1,2,3]).all()
  4223. True
  4224. >>> a = np.ma.array([1,2,3], mask=True)
  4225. >>> (a.all() is np.ma.masked)
  4226. True
  4227. """
  4228. kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
  4229. mask = _check_mask_axis(self._mask, axis, **kwargs)
  4230. if out is None:
  4231. d = self.filled(True).all(axis=axis, **kwargs).view(type(self))
  4232. if d.ndim:
  4233. d.__setmask__(mask)
  4234. elif mask:
  4235. return masked
  4236. return d
  4237. self.filled(True).all(axis=axis, out=out, **kwargs)
  4238. if isinstance(out, MaskedArray):
  4239. if out.ndim or mask:
  4240. out.__setmask__(mask)
  4241. return out
  4242. def any(self, axis=None, out=None, keepdims=np._NoValue):
  4243. """
  4244. Returns True if any of the elements of `a` evaluate to True.
  4245. Masked values are considered as False during computation.
  4246. Refer to `numpy.any` for full documentation.
  4247. See Also
  4248. --------
  4249. numpy.ndarray.any : corresponding function for ndarrays
  4250. numpy.any : equivalent function
  4251. """
  4252. kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
  4253. mask = _check_mask_axis(self._mask, axis, **kwargs)
  4254. if out is None:
  4255. d = self.filled(False).any(axis=axis, **kwargs).view(type(self))
  4256. if d.ndim:
  4257. d.__setmask__(mask)
  4258. elif mask:
  4259. d = masked
  4260. return d
  4261. self.filled(False).any(axis=axis, out=out, **kwargs)
  4262. if isinstance(out, MaskedArray):
  4263. if out.ndim or mask:
  4264. out.__setmask__(mask)
  4265. return out
  4266. def nonzero(self):
  4267. """
  4268. Return the indices of unmasked elements that are not zero.
  4269. Returns a tuple of arrays, one for each dimension, containing the
  4270. indices of the non-zero elements in that dimension. The corresponding
  4271. non-zero values can be obtained with::
  4272. a[a.nonzero()]
  4273. To group the indices by element, rather than dimension, use
  4274. instead::
  4275. np.transpose(a.nonzero())
  4276. The result of this is always a 2d array, with a row for each non-zero
  4277. element.
  4278. Parameters
  4279. ----------
  4280. None
  4281. Returns
  4282. -------
  4283. tuple_of_arrays : tuple
  4284. Indices of elements that are non-zero.
  4285. See Also
  4286. --------
  4287. numpy.nonzero :
  4288. Function operating on ndarrays.
  4289. flatnonzero :
  4290. Return indices that are non-zero in the flattened version of the input
  4291. array.
  4292. numpy.ndarray.nonzero :
  4293. Equivalent ndarray method.
  4294. count_nonzero :
  4295. Counts the number of non-zero elements in the input array.
  4296. Examples
  4297. --------
  4298. >>> import numpy as np
  4299. >>> import numpy.ma as ma
  4300. >>> x = ma.array(np.eye(3))
  4301. >>> x
  4302. masked_array(
  4303. data=[[1., 0., 0.],
  4304. [0., 1., 0.],
  4305. [0., 0., 1.]],
  4306. mask=False,
  4307. fill_value=1e+20)
  4308. >>> x.nonzero()
  4309. (array([0, 1, 2]), array([0, 1, 2]))
  4310. Masked elements are ignored.
  4311. >>> x[1, 1] = ma.masked
  4312. >>> x
  4313. masked_array(
  4314. data=[[1.0, 0.0, 0.0],
  4315. [0.0, --, 0.0],
  4316. [0.0, 0.0, 1.0]],
  4317. mask=[[False, False, False],
  4318. [False, True, False],
  4319. [False, False, False]],
  4320. fill_value=1e+20)
  4321. >>> x.nonzero()
  4322. (array([0, 2]), array([0, 2]))
  4323. Indices can also be grouped by element.
  4324. >>> np.transpose(x.nonzero())
  4325. array([[0, 0],
  4326. [2, 2]])
  4327. A common use for ``nonzero`` is to find the indices of an array, where
  4328. a condition is True. Given an array `a`, the condition `a` > 3 is a
  4329. boolean array and since False is interpreted as 0, ma.nonzero(a > 3)
  4330. yields the indices of the `a` where the condition is true.
  4331. >>> a = ma.array([[1,2,3],[4,5,6],[7,8,9]])
  4332. >>> a > 3
  4333. masked_array(
  4334. data=[[False, False, False],
  4335. [ True, True, True],
  4336. [ True, True, True]],
  4337. mask=False,
  4338. fill_value=True)
  4339. >>> ma.nonzero(a > 3)
  4340. (array([1, 1, 1, 2, 2, 2]), array([0, 1, 2, 0, 1, 2]))
  4341. The ``nonzero`` method of the condition array can also be called.
  4342. >>> (a > 3).nonzero()
  4343. (array([1, 1, 1, 2, 2, 2]), array([0, 1, 2, 0, 1, 2]))
  4344. """
  4345. return np.asarray(self.filled(0)).nonzero()
  4346. def trace(self, offset=0, axis1=0, axis2=1, dtype=None, out=None):
  4347. """
  4348. (this docstring should be overwritten)
  4349. """
  4350. #!!!: implement out + test!
  4351. m = self._mask
  4352. if m is nomask:
  4353. result = super().trace(offset=offset, axis1=axis1, axis2=axis2,
  4354. out=out)
  4355. return result.astype(dtype)
  4356. else:
  4357. D = self.diagonal(offset=offset, axis1=axis1, axis2=axis2)
  4358. return D.astype(dtype).filled(0).sum(axis=-1, out=out)
  4359. trace.__doc__ = ndarray.trace.__doc__
  4360. def dot(self, b, out=None, strict=False):
  4361. """
  4362. a.dot(b, out=None)
  4363. Masked dot product of two arrays. Note that `out` and `strict` are
  4364. located in different positions than in `ma.dot`. In order to
  4365. maintain compatibility with the functional version, it is
  4366. recommended that the optional arguments be treated as keyword only.
  4367. At some point that may be mandatory.
  4368. Parameters
  4369. ----------
  4370. b : masked_array_like
  4371. Inputs array.
  4372. out : masked_array, optional
  4373. Output argument. This must have the exact kind that would be
  4374. returned if it was not used. In particular, it must have the
  4375. right type, must be C-contiguous, and its dtype must be the
  4376. dtype that would be returned for `ma.dot(a,b)`. This is a
  4377. performance feature. Therefore, if these conditions are not
  4378. met, an exception is raised, instead of attempting to be
  4379. flexible.
  4380. strict : bool, optional
  4381. Whether masked data are propagated (True) or set to 0 (False)
  4382. for the computation. Default is False. Propagating the mask
  4383. means that if a masked value appears in a row or column, the
  4384. whole row or column is considered masked.
  4385. See Also
  4386. --------
  4387. numpy.ma.dot : equivalent function
  4388. """
  4389. return dot(self, b, out=out, strict=strict)
  4390. def sum(self, axis=None, dtype=None, out=None, keepdims=np._NoValue):
  4391. """
  4392. Return the sum of the array elements over the given axis.
  4393. Masked elements are set to 0 internally.
  4394. Refer to `numpy.sum` for full documentation.
  4395. See Also
  4396. --------
  4397. numpy.ndarray.sum : corresponding function for ndarrays
  4398. numpy.sum : equivalent function
  4399. Examples
  4400. --------
  4401. >>> import numpy as np
  4402. >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4)
  4403. >>> x
  4404. masked_array(
  4405. data=[[1, --, 3],
  4406. [--, 5, --],
  4407. [7, --, 9]],
  4408. mask=[[False, True, False],
  4409. [ True, False, True],
  4410. [False, True, False]],
  4411. fill_value=999999)
  4412. >>> x.sum()
  4413. 25
  4414. >>> x.sum(axis=1)
  4415. masked_array(data=[4, 5, 16],
  4416. mask=[False, False, False],
  4417. fill_value=999999)
  4418. >>> x.sum(axis=0)
  4419. masked_array(data=[8, 5, 12],
  4420. mask=[False, False, False],
  4421. fill_value=999999)
  4422. >>> print(type(x.sum(axis=0, dtype=np.int64)[0]))
  4423. <class 'numpy.int64'>
  4424. """
  4425. kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
  4426. _mask = self._mask
  4427. newmask = _check_mask_axis(_mask, axis, **kwargs)
  4428. # No explicit output
  4429. if out is None:
  4430. result = self.filled(0).sum(axis, dtype=dtype, **kwargs)
  4431. rndim = getattr(result, 'ndim', 0)
  4432. if rndim:
  4433. result = result.view(type(self))
  4434. result.__setmask__(newmask)
  4435. elif newmask:
  4436. result = masked
  4437. return result
  4438. # Explicit output
  4439. result = self.filled(0).sum(axis, dtype=dtype, out=out, **kwargs)
  4440. if isinstance(out, MaskedArray):
  4441. outmask = getmask(out)
  4442. if outmask is nomask:
  4443. outmask = out._mask = make_mask_none(out.shape)
  4444. outmask.flat = newmask
  4445. return out
  4446. def cumsum(self, axis=None, dtype=None, out=None):
  4447. """
  4448. Return the cumulative sum of the array elements over the given axis.
  4449. Masked values are set to 0 internally during the computation.
  4450. However, their position is saved, and the result will be masked at
  4451. the same locations.
  4452. Refer to `numpy.cumsum` for full documentation.
  4453. Notes
  4454. -----
  4455. The mask is lost if `out` is not a valid :class:`ma.MaskedArray` !
  4456. Arithmetic is modular when using integer types, and no error is
  4457. raised on overflow.
  4458. See Also
  4459. --------
  4460. numpy.ndarray.cumsum : corresponding function for ndarrays
  4461. numpy.cumsum : equivalent function
  4462. Examples
  4463. --------
  4464. >>> import numpy as np
  4465. >>> marr = np.ma.array(np.arange(10), mask=[0,0,0,1,1,1,0,0,0,0])
  4466. >>> marr.cumsum()
  4467. masked_array(data=[0, 1, 3, --, --, --, 9, 16, 24, 33],
  4468. mask=[False, False, False, True, True, True, False, False,
  4469. False, False],
  4470. fill_value=999999)
  4471. """
  4472. result = self.filled(0).cumsum(axis=axis, dtype=dtype, out=out)
  4473. if out is not None:
  4474. if isinstance(out, MaskedArray):
  4475. out.__setmask__(self.mask)
  4476. return out
  4477. result = result.view(type(self))
  4478. result.__setmask__(self._mask)
  4479. return result
  4480. def prod(self, axis=None, dtype=None, out=None, keepdims=np._NoValue):
  4481. """
  4482. Return the product of the array elements over the given axis.
  4483. Masked elements are set to 1 internally for computation.
  4484. Refer to `numpy.prod` for full documentation.
  4485. Notes
  4486. -----
  4487. Arithmetic is modular when using integer types, and no error is raised
  4488. on overflow.
  4489. See Also
  4490. --------
  4491. numpy.ndarray.prod : corresponding function for ndarrays
  4492. numpy.prod : equivalent function
  4493. """
  4494. kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
  4495. _mask = self._mask
  4496. newmask = _check_mask_axis(_mask, axis, **kwargs)
  4497. # No explicit output
  4498. if out is None:
  4499. result = self.filled(1).prod(axis, dtype=dtype, **kwargs)
  4500. rndim = getattr(result, 'ndim', 0)
  4501. if rndim:
  4502. result = result.view(type(self))
  4503. result.__setmask__(newmask)
  4504. elif newmask:
  4505. result = masked
  4506. return result
  4507. # Explicit output
  4508. result = self.filled(1).prod(axis, dtype=dtype, out=out, **kwargs)
  4509. if isinstance(out, MaskedArray):
  4510. outmask = getmask(out)
  4511. if outmask is nomask:
  4512. outmask = out._mask = make_mask_none(out.shape)
  4513. outmask.flat = newmask
  4514. return out
  4515. product = prod
  4516. def cumprod(self, axis=None, dtype=None, out=None):
  4517. """
  4518. Return the cumulative product of the array elements over the given axis.
  4519. Masked values are set to 1 internally during the computation.
  4520. However, their position is saved, and the result will be masked at
  4521. the same locations.
  4522. Refer to `numpy.cumprod` for full documentation.
  4523. Notes
  4524. -----
  4525. The mask is lost if `out` is not a valid MaskedArray !
  4526. Arithmetic is modular when using integer types, and no error is
  4527. raised on overflow.
  4528. See Also
  4529. --------
  4530. numpy.ndarray.cumprod : corresponding function for ndarrays
  4531. numpy.cumprod : equivalent function
  4532. """
  4533. result = self.filled(1).cumprod(axis=axis, dtype=dtype, out=out)
  4534. if out is not None:
  4535. if isinstance(out, MaskedArray):
  4536. out.__setmask__(self._mask)
  4537. return out
  4538. result = result.view(type(self))
  4539. result.__setmask__(self._mask)
  4540. return result
  4541. def mean(self, axis=None, dtype=None, out=None, keepdims=np._NoValue):
  4542. """
  4543. Returns the average of the array elements along given axis.
  4544. Masked entries are ignored, and result elements which are not
  4545. finite will be masked.
  4546. Refer to `numpy.mean` for full documentation.
  4547. See Also
  4548. --------
  4549. numpy.ndarray.mean : corresponding function for ndarrays
  4550. numpy.mean : Equivalent function
  4551. numpy.ma.average : Weighted average.
  4552. Examples
  4553. --------
  4554. >>> import numpy as np
  4555. >>> a = np.ma.array([1,2,3], mask=[False, False, True])
  4556. >>> a
  4557. masked_array(data=[1, 2, --],
  4558. mask=[False, False, True],
  4559. fill_value=999999)
  4560. >>> a.mean()
  4561. 1.5
  4562. """
  4563. kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
  4564. if self._mask is nomask:
  4565. result = super().mean(axis=axis, dtype=dtype, **kwargs)[()]
  4566. else:
  4567. is_float16_result = False
  4568. if dtype is None:
  4569. if issubclass(self.dtype.type, (ntypes.integer, ntypes.bool)):
  4570. dtype = mu.dtype('f8')
  4571. elif issubclass(self.dtype.type, ntypes.float16):
  4572. dtype = mu.dtype('f4')
  4573. is_float16_result = True
  4574. dsum = self.sum(axis=axis, dtype=dtype, **kwargs)
  4575. cnt = self.count(axis=axis, **kwargs)
  4576. if cnt.shape == () and (cnt == 0):
  4577. result = masked
  4578. elif is_float16_result:
  4579. result = self.dtype.type(dsum * 1. / cnt)
  4580. else:
  4581. result = dsum * 1. / cnt
  4582. if out is not None:
  4583. out.flat = result
  4584. if isinstance(out, MaskedArray):
  4585. outmask = getmask(out)
  4586. if outmask is nomask:
  4587. outmask = out._mask = make_mask_none(out.shape)
  4588. outmask.flat = getmask(result)
  4589. return out
  4590. return result
  4591. def anom(self, axis=None, dtype=None):
  4592. """
  4593. Compute the anomalies (deviations from the arithmetic mean)
  4594. along the given axis.
  4595. Returns an array of anomalies, with the same shape as the input and
  4596. where the arithmetic mean is computed along the given axis.
  4597. Parameters
  4598. ----------
  4599. axis : int, optional
  4600. Axis over which the anomalies are taken.
  4601. The default is to use the mean of the flattened array as reference.
  4602. dtype : dtype, optional
  4603. Type to use in computing the variance. For arrays of integer type
  4604. the default is float32; for arrays of float types it is the same as
  4605. the array type.
  4606. See Also
  4607. --------
  4608. mean : Compute the mean of the array.
  4609. Examples
  4610. --------
  4611. >>> import numpy as np
  4612. >>> a = np.ma.array([1,2,3])
  4613. >>> a.anom()
  4614. masked_array(data=[-1., 0., 1.],
  4615. mask=False,
  4616. fill_value=1e+20)
  4617. """
  4618. m = self.mean(axis, dtype)
  4619. if not axis:
  4620. return self - m
  4621. else:
  4622. return self - expand_dims(m, axis)
  4623. def var(self, axis=None, dtype=None, out=None, ddof=0,
  4624. keepdims=np._NoValue, mean=np._NoValue):
  4625. """
  4626. Returns the variance of the array elements along given axis.
  4627. Masked entries are ignored, and result elements which are not
  4628. finite will be masked.
  4629. Refer to `numpy.var` for full documentation.
  4630. See Also
  4631. --------
  4632. numpy.ndarray.var : corresponding function for ndarrays
  4633. numpy.var : Equivalent function
  4634. """
  4635. kwargs = {}
  4636. if keepdims is not np._NoValue:
  4637. kwargs['keepdims'] = keepdims
  4638. # Easy case: nomask, business as usual
  4639. if self._mask is nomask:
  4640. if mean is not np._NoValue:
  4641. kwargs['mean'] = mean
  4642. ret = super().var(axis=axis, dtype=dtype, out=out, ddof=ddof,
  4643. **kwargs)[()]
  4644. if out is not None:
  4645. if isinstance(out, MaskedArray):
  4646. out.__setmask__(nomask)
  4647. return out
  4648. return ret
  4649. # Some data are masked, yay!
  4650. cnt = self.count(axis=axis, **kwargs) - ddof
  4651. if mean is not np._NoValue:
  4652. danom = self - mean
  4653. else:
  4654. danom = self - self.mean(axis, dtype, keepdims=True)
  4655. if iscomplexobj(self):
  4656. danom = umath.absolute(danom) ** 2
  4657. else:
  4658. danom *= danom
  4659. dvar = divide(danom.sum(axis, **kwargs), cnt).view(type(self))
  4660. # Apply the mask if it's not a scalar
  4661. if dvar.ndim:
  4662. dvar._mask = mask_or(self._mask.all(axis, **kwargs), (cnt <= 0))
  4663. dvar._update_from(self)
  4664. elif getmask(dvar):
  4665. # Make sure that masked is returned when the scalar is masked.
  4666. dvar = masked
  4667. if out is not None:
  4668. if isinstance(out, MaskedArray):
  4669. out.flat = 0
  4670. out.__setmask__(True)
  4671. elif out.dtype.kind in 'biu':
  4672. errmsg = "Masked data information would be lost in one or "\
  4673. "more location."
  4674. raise MaskError(errmsg)
  4675. else:
  4676. out.flat = np.nan
  4677. return out
  4678. # In case with have an explicit output
  4679. if out is not None:
  4680. # Set the data
  4681. out.flat = dvar
  4682. # Set the mask if needed
  4683. if isinstance(out, MaskedArray):
  4684. out.__setmask__(dvar.mask)
  4685. return out
  4686. return dvar
  4687. var.__doc__ = np.var.__doc__
  4688. def std(self, axis=None, dtype=None, out=None, ddof=0,
  4689. keepdims=np._NoValue, mean=np._NoValue):
  4690. """
  4691. Returns the standard deviation of the array elements along given axis.
  4692. Masked entries are ignored.
  4693. Refer to `numpy.std` for full documentation.
  4694. See Also
  4695. --------
  4696. numpy.ndarray.std : corresponding function for ndarrays
  4697. numpy.std : Equivalent function
  4698. """
  4699. kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
  4700. dvar = self.var(axis, dtype, out, ddof, **kwargs)
  4701. if dvar is not masked:
  4702. if out is not None:
  4703. np.power(out, 0.5, out=out, casting='unsafe')
  4704. return out
  4705. dvar = sqrt(dvar)
  4706. return dvar
  4707. def round(self, decimals=0, out=None):
  4708. """
  4709. Return each element rounded to the given number of decimals.
  4710. Refer to `numpy.around` for full documentation.
  4711. See Also
  4712. --------
  4713. numpy.ndarray.round : corresponding function for ndarrays
  4714. numpy.around : equivalent function
  4715. Examples
  4716. --------
  4717. >>> import numpy as np
  4718. >>> import numpy.ma as ma
  4719. >>> x = ma.array([1.35, 2.5, 1.5, 1.75, 2.25, 2.75],
  4720. ... mask=[0, 0, 0, 1, 0, 0])
  4721. >>> ma.round(x)
  4722. masked_array(data=[1.0, 2.0, 2.0, --, 2.0, 3.0],
  4723. mask=[False, False, False, True, False, False],
  4724. fill_value=1e+20)
  4725. """
  4726. result = self._data.round(decimals=decimals, out=out).view(type(self))
  4727. if result.ndim > 0:
  4728. result._mask = self._mask
  4729. result._update_from(self)
  4730. elif self._mask:
  4731. # Return masked when the scalar is masked
  4732. result = masked
  4733. # No explicit output: we're done
  4734. if out is None:
  4735. return result
  4736. if isinstance(out, MaskedArray):
  4737. out.__setmask__(self._mask)
  4738. return out
  4739. def argsort(self, axis=np._NoValue, kind=None, order=None, endwith=True,
  4740. fill_value=None, *, stable=False):
  4741. """
  4742. Return an ndarray of indices that sort the array along the
  4743. specified axis. Masked values are filled beforehand to
  4744. `fill_value`.
  4745. Parameters
  4746. ----------
  4747. axis : int, optional
  4748. Axis along which to sort. If None, the default, the flattened array
  4749. is used.
  4750. kind : {'quicksort', 'mergesort', 'heapsort', 'stable'}, optional
  4751. The sorting algorithm used.
  4752. order : list, optional
  4753. When `a` is an array with fields defined, this argument specifies
  4754. which fields to compare first, second, etc. Not all fields need be
  4755. specified.
  4756. endwith : {True, False}, optional
  4757. Whether missing values (if any) should be treated as the largest values
  4758. (True) or the smallest values (False)
  4759. When the array contains unmasked values at the same extremes of the
  4760. datatype, the ordering of these values and the masked values is
  4761. undefined.
  4762. fill_value : scalar or None, optional
  4763. Value used internally for the masked values.
  4764. If ``fill_value`` is not None, it supersedes ``endwith``.
  4765. stable : bool, optional
  4766. Only for compatibility with ``np.argsort``. Ignored.
  4767. Returns
  4768. -------
  4769. index_array : ndarray, int
  4770. Array of indices that sort `a` along the specified axis.
  4771. In other words, ``a[index_array]`` yields a sorted `a`.
  4772. See Also
  4773. --------
  4774. ma.MaskedArray.sort : Describes sorting algorithms used.
  4775. lexsort : Indirect stable sort with multiple keys.
  4776. numpy.ndarray.sort : Inplace sort.
  4777. Notes
  4778. -----
  4779. See `sort` for notes on the different sorting algorithms.
  4780. Examples
  4781. --------
  4782. >>> import numpy as np
  4783. >>> a = np.ma.array([3,2,1], mask=[False, False, True])
  4784. >>> a
  4785. masked_array(data=[3, 2, --],
  4786. mask=[False, False, True],
  4787. fill_value=999999)
  4788. >>> a.argsort()
  4789. array([1, 0, 2])
  4790. """
  4791. if stable:
  4792. raise ValueError(
  4793. "`stable` parameter is not supported for masked arrays."
  4794. )
  4795. # 2017-04-11, Numpy 1.13.0, gh-8701: warn on axis default
  4796. if axis is np._NoValue:
  4797. axis = _deprecate_argsort_axis(self)
  4798. if fill_value is None:
  4799. if endwith:
  4800. # nan > inf
  4801. if np.issubdtype(self.dtype, np.floating):
  4802. fill_value = np.nan
  4803. else:
  4804. fill_value = minimum_fill_value(self)
  4805. else:
  4806. fill_value = maximum_fill_value(self)
  4807. filled = self.filled(fill_value)
  4808. return filled.argsort(axis=axis, kind=kind, order=order)
  4809. def argmin(self, axis=None, fill_value=None, out=None, *,
  4810. keepdims=np._NoValue):
  4811. """
  4812. Return array of indices to the minimum values along the given axis.
  4813. Parameters
  4814. ----------
  4815. axis : {None, integer}
  4816. If None, the index is into the flattened array, otherwise along
  4817. the specified axis
  4818. fill_value : scalar or None, optional
  4819. Value used to fill in the masked values. If None, the output of
  4820. minimum_fill_value(self._data) is used instead.
  4821. out : {None, array}, optional
  4822. Array into which the result can be placed. Its type is preserved
  4823. and it must be of the right shape to hold the output.
  4824. Returns
  4825. -------
  4826. ndarray or scalar
  4827. If multi-dimension input, returns a new ndarray of indices to the
  4828. minimum values along the given axis. Otherwise, returns a scalar
  4829. of index to the minimum values along the given axis.
  4830. Examples
  4831. --------
  4832. >>> import numpy as np
  4833. >>> x = np.ma.array(np.arange(4), mask=[1,1,0,0])
  4834. >>> x.shape = (2,2)
  4835. >>> x
  4836. masked_array(
  4837. data=[[--, --],
  4838. [2, 3]],
  4839. mask=[[ True, True],
  4840. [False, False]],
  4841. fill_value=999999)
  4842. >>> x.argmin(axis=0, fill_value=-1)
  4843. array([0, 0])
  4844. >>> x.argmin(axis=0, fill_value=9)
  4845. array([1, 1])
  4846. """
  4847. if fill_value is None:
  4848. fill_value = minimum_fill_value(self)
  4849. d = self.filled(fill_value).view(ndarray)
  4850. keepdims = False if keepdims is np._NoValue else bool(keepdims)
  4851. return d.argmin(axis, out=out, keepdims=keepdims)
  4852. def argmax(self, axis=None, fill_value=None, out=None, *,
  4853. keepdims=np._NoValue):
  4854. """
  4855. Returns array of indices of the maximum values along the given axis.
  4856. Masked values are treated as if they had the value fill_value.
  4857. Parameters
  4858. ----------
  4859. axis : {None, integer}
  4860. If None, the index is into the flattened array, otherwise along
  4861. the specified axis
  4862. fill_value : scalar or None, optional
  4863. Value used to fill in the masked values. If None, the output of
  4864. maximum_fill_value(self._data) is used instead.
  4865. out : {None, array}, optional
  4866. Array into which the result can be placed. Its type is preserved
  4867. and it must be of the right shape to hold the output.
  4868. Returns
  4869. -------
  4870. index_array : {integer_array}
  4871. Examples
  4872. --------
  4873. >>> import numpy as np
  4874. >>> a = np.arange(6).reshape(2,3)
  4875. >>> a.argmax()
  4876. 5
  4877. >>> a.argmax(0)
  4878. array([1, 1, 1])
  4879. >>> a.argmax(1)
  4880. array([2, 2])
  4881. """
  4882. if fill_value is None:
  4883. fill_value = maximum_fill_value(self._data)
  4884. d = self.filled(fill_value).view(ndarray)
  4885. keepdims = False if keepdims is np._NoValue else bool(keepdims)
  4886. return d.argmax(axis, out=out, keepdims=keepdims)
  4887. def sort(self, axis=-1, kind=None, order=None, endwith=True,
  4888. fill_value=None, *, stable=False):
  4889. """
  4890. Sort the array, in-place
  4891. Parameters
  4892. ----------
  4893. a : array_like
  4894. Array to be sorted.
  4895. axis : int, optional
  4896. Axis along which to sort. If None, the array is flattened before
  4897. sorting. The default is -1, which sorts along the last axis.
  4898. kind : {'quicksort', 'mergesort', 'heapsort', 'stable'}, optional
  4899. The sorting algorithm used.
  4900. order : list, optional
  4901. When `a` is a structured array, this argument specifies which fields
  4902. to compare first, second, and so on. This list does not need to
  4903. include all of the fields.
  4904. endwith : {True, False}, optional
  4905. Whether missing values (if any) should be treated as the largest values
  4906. (True) or the smallest values (False)
  4907. When the array contains unmasked values sorting at the same extremes of the
  4908. datatype, the ordering of these values and the masked values is
  4909. undefined.
  4910. fill_value : scalar or None, optional
  4911. Value used internally for the masked values.
  4912. If ``fill_value`` is not None, it supersedes ``endwith``.
  4913. stable : bool, optional
  4914. Only for compatibility with ``np.sort``. Ignored.
  4915. Returns
  4916. -------
  4917. sorted_array : ndarray
  4918. Array of the same type and shape as `a`.
  4919. See Also
  4920. --------
  4921. numpy.ndarray.sort : Method to sort an array in-place.
  4922. argsort : Indirect sort.
  4923. lexsort : Indirect stable sort on multiple keys.
  4924. searchsorted : Find elements in a sorted array.
  4925. Notes
  4926. -----
  4927. See ``sort`` for notes on the different sorting algorithms.
  4928. Examples
  4929. --------
  4930. >>> import numpy as np
  4931. >>> a = np.ma.array([1, 2, 5, 4, 3],mask=[0, 1, 0, 1, 0])
  4932. >>> # Default
  4933. >>> a.sort()
  4934. >>> a
  4935. masked_array(data=[1, 3, 5, --, --],
  4936. mask=[False, False, False, True, True],
  4937. fill_value=999999)
  4938. >>> a = np.ma.array([1, 2, 5, 4, 3],mask=[0, 1, 0, 1, 0])
  4939. >>> # Put missing values in the front
  4940. >>> a.sort(endwith=False)
  4941. >>> a
  4942. masked_array(data=[--, --, 1, 3, 5],
  4943. mask=[ True, True, False, False, False],
  4944. fill_value=999999)
  4945. >>> a = np.ma.array([1, 2, 5, 4, 3],mask=[0, 1, 0, 1, 0])
  4946. >>> # fill_value takes over endwith
  4947. >>> a.sort(endwith=False, fill_value=3)
  4948. >>> a
  4949. masked_array(data=[1, --, --, 3, 5],
  4950. mask=[False, True, True, False, False],
  4951. fill_value=999999)
  4952. """
  4953. if stable:
  4954. raise ValueError(
  4955. "`stable` parameter is not supported for masked arrays."
  4956. )
  4957. if self._mask is nomask:
  4958. ndarray.sort(self, axis=axis, kind=kind, order=order)
  4959. return
  4960. if self is masked:
  4961. return
  4962. sidx = self.argsort(axis=axis, kind=kind, order=order,
  4963. fill_value=fill_value, endwith=endwith)
  4964. self[...] = np.take_along_axis(self, sidx, axis=axis)
  4965. def min(self, axis=None, out=None, fill_value=None, keepdims=np._NoValue):
  4966. """
  4967. Return the minimum along a given axis.
  4968. Parameters
  4969. ----------
  4970. axis : None or int or tuple of ints, optional
  4971. Axis along which to operate. By default, ``axis`` is None and the
  4972. flattened input is used.
  4973. If this is a tuple of ints, the minimum is selected over multiple
  4974. axes, instead of a single axis or all the axes as before.
  4975. out : array_like, optional
  4976. Alternative output array in which to place the result. Must be of
  4977. the same shape and buffer length as the expected output.
  4978. fill_value : scalar or None, optional
  4979. Value used to fill in the masked values.
  4980. If None, use the output of `minimum_fill_value`.
  4981. keepdims : bool, optional
  4982. If this is set to True, the axes which are reduced are left
  4983. in the result as dimensions with size one. With this option,
  4984. the result will broadcast correctly against the array.
  4985. Returns
  4986. -------
  4987. amin : array_like
  4988. New array holding the result.
  4989. If ``out`` was specified, ``out`` is returned.
  4990. See Also
  4991. --------
  4992. ma.minimum_fill_value
  4993. Returns the minimum filling value for a given datatype.
  4994. Examples
  4995. --------
  4996. >>> import numpy.ma as ma
  4997. >>> x = [[1., -2., 3.], [0.2, -0.7, 0.1]]
  4998. >>> mask = [[1, 1, 0], [0, 0, 1]]
  4999. >>> masked_x = ma.masked_array(x, mask)
  5000. >>> masked_x
  5001. masked_array(
  5002. data=[[--, --, 3.0],
  5003. [0.2, -0.7, --]],
  5004. mask=[[ True, True, False],
  5005. [False, False, True]],
  5006. fill_value=1e+20)
  5007. >>> ma.min(masked_x)
  5008. -0.7
  5009. >>> ma.min(masked_x, axis=-1)
  5010. masked_array(data=[3.0, -0.7],
  5011. mask=[False, False],
  5012. fill_value=1e+20)
  5013. >>> ma.min(masked_x, axis=0, keepdims=True)
  5014. masked_array(data=[[0.2, -0.7, 3.0]],
  5015. mask=[[False, False, False]],
  5016. fill_value=1e+20)
  5017. >>> mask = [[1, 1, 1,], [1, 1, 1]]
  5018. >>> masked_x = ma.masked_array(x, mask)
  5019. >>> ma.min(masked_x, axis=0)
  5020. masked_array(data=[--, --, --],
  5021. mask=[ True, True, True],
  5022. fill_value=1e+20,
  5023. dtype=float64)
  5024. """
  5025. kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
  5026. _mask = self._mask
  5027. newmask = _check_mask_axis(_mask, axis, **kwargs)
  5028. if fill_value is None:
  5029. fill_value = minimum_fill_value(self)
  5030. # No explicit output
  5031. if out is None:
  5032. result = self.filled(fill_value).min(
  5033. axis=axis, out=out, **kwargs).view(type(self))
  5034. if result.ndim:
  5035. # Set the mask
  5036. result.__setmask__(newmask)
  5037. # Get rid of Infs
  5038. if newmask.ndim:
  5039. np.copyto(result, result.fill_value, where=newmask)
  5040. elif newmask:
  5041. result = masked
  5042. return result
  5043. # Explicit output
  5044. self.filled(fill_value).min(axis=axis, out=out, **kwargs)
  5045. if isinstance(out, MaskedArray):
  5046. outmask = getmask(out)
  5047. if outmask is nomask:
  5048. outmask = out._mask = make_mask_none(out.shape)
  5049. outmask.flat = newmask
  5050. else:
  5051. if out.dtype.kind in 'biu':
  5052. errmsg = "Masked data information would be lost in one or more"\
  5053. " location."
  5054. raise MaskError(errmsg)
  5055. np.copyto(out, np.nan, where=newmask)
  5056. return out
  5057. def max(self, axis=None, out=None, fill_value=None, keepdims=np._NoValue):
  5058. """
  5059. Return the maximum along a given axis.
  5060. Parameters
  5061. ----------
  5062. axis : None or int or tuple of ints, optional
  5063. Axis along which to operate. By default, ``axis`` is None and the
  5064. flattened input is used.
  5065. If this is a tuple of ints, the maximum is selected over multiple
  5066. axes, instead of a single axis or all the axes as before.
  5067. out : array_like, optional
  5068. Alternative output array in which to place the result. Must
  5069. be of the same shape and buffer length as the expected output.
  5070. fill_value : scalar or None, optional
  5071. Value used to fill in the masked values.
  5072. If None, use the output of maximum_fill_value().
  5073. keepdims : bool, optional
  5074. If this is set to True, the axes which are reduced are left
  5075. in the result as dimensions with size one. With this option,
  5076. the result will broadcast correctly against the array.
  5077. Returns
  5078. -------
  5079. amax : array_like
  5080. New array holding the result.
  5081. If ``out`` was specified, ``out`` is returned.
  5082. See Also
  5083. --------
  5084. ma.maximum_fill_value
  5085. Returns the maximum filling value for a given datatype.
  5086. Examples
  5087. --------
  5088. >>> import numpy.ma as ma
  5089. >>> x = [[-1., 2.5], [4., -2.], [3., 0.]]
  5090. >>> mask = [[0, 0], [1, 0], [1, 0]]
  5091. >>> masked_x = ma.masked_array(x, mask)
  5092. >>> masked_x
  5093. masked_array(
  5094. data=[[-1.0, 2.5],
  5095. [--, -2.0],
  5096. [--, 0.0]],
  5097. mask=[[False, False],
  5098. [ True, False],
  5099. [ True, False]],
  5100. fill_value=1e+20)
  5101. >>> ma.max(masked_x)
  5102. 2.5
  5103. >>> ma.max(masked_x, axis=0)
  5104. masked_array(data=[-1.0, 2.5],
  5105. mask=[False, False],
  5106. fill_value=1e+20)
  5107. >>> ma.max(masked_x, axis=1, keepdims=True)
  5108. masked_array(
  5109. data=[[2.5],
  5110. [-2.0],
  5111. [0.0]],
  5112. mask=[[False],
  5113. [False],
  5114. [False]],
  5115. fill_value=1e+20)
  5116. >>> mask = [[1, 1], [1, 1], [1, 1]]
  5117. >>> masked_x = ma.masked_array(x, mask)
  5118. >>> ma.max(masked_x, axis=1)
  5119. masked_array(data=[--, --, --],
  5120. mask=[ True, True, True],
  5121. fill_value=1e+20,
  5122. dtype=float64)
  5123. """
  5124. kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
  5125. _mask = self._mask
  5126. newmask = _check_mask_axis(_mask, axis, **kwargs)
  5127. if fill_value is None:
  5128. fill_value = maximum_fill_value(self)
  5129. # No explicit output
  5130. if out is None:
  5131. result = self.filled(fill_value).max(
  5132. axis=axis, out=out, **kwargs).view(type(self))
  5133. if result.ndim:
  5134. # Set the mask
  5135. result.__setmask__(newmask)
  5136. # Get rid of Infs
  5137. if newmask.ndim:
  5138. np.copyto(result, result.fill_value, where=newmask)
  5139. elif newmask:
  5140. result = masked
  5141. return result
  5142. # Explicit output
  5143. self.filled(fill_value).max(axis=axis, out=out, **kwargs)
  5144. if isinstance(out, MaskedArray):
  5145. outmask = getmask(out)
  5146. if outmask is nomask:
  5147. outmask = out._mask = make_mask_none(out.shape)
  5148. outmask.flat = newmask
  5149. else:
  5150. if out.dtype.kind in 'biu':
  5151. errmsg = "Masked data information would be lost in one or more"\
  5152. " location."
  5153. raise MaskError(errmsg)
  5154. np.copyto(out, np.nan, where=newmask)
  5155. return out
  5156. def ptp(self, axis=None, out=None, fill_value=None, keepdims=False):
  5157. """
  5158. Return (maximum - minimum) along the given dimension
  5159. (i.e. peak-to-peak value).
  5160. .. warning::
  5161. `ptp` preserves the data type of the array. This means the
  5162. return value for an input of signed integers with n bits
  5163. (e.g. `np.int8`, `np.int16`, etc) is also a signed integer
  5164. with n bits. In that case, peak-to-peak values greater than
  5165. ``2**(n-1)-1`` will be returned as negative values. An example
  5166. with a work-around is shown below.
  5167. Parameters
  5168. ----------
  5169. axis : {None, int}, optional
  5170. Axis along which to find the peaks. If None (default) the
  5171. flattened array is used.
  5172. out : {None, array_like}, optional
  5173. Alternative output array in which to place the result. It must
  5174. have the same shape and buffer length as the expected output
  5175. but the type will be cast if necessary.
  5176. fill_value : scalar or None, optional
  5177. Value used to fill in the masked values.
  5178. keepdims : bool, optional
  5179. If this is set to True, the axes which are reduced are left
  5180. in the result as dimensions with size one. With this option,
  5181. the result will broadcast correctly against the array.
  5182. Returns
  5183. -------
  5184. ptp : ndarray.
  5185. A new array holding the result, unless ``out`` was
  5186. specified, in which case a reference to ``out`` is returned.
  5187. Examples
  5188. --------
  5189. >>> import numpy as np
  5190. >>> x = np.ma.MaskedArray([[4, 9, 2, 10],
  5191. ... [6, 9, 7, 12]])
  5192. >>> x.ptp(axis=1)
  5193. masked_array(data=[8, 6],
  5194. mask=False,
  5195. fill_value=999999)
  5196. >>> x.ptp(axis=0)
  5197. masked_array(data=[2, 0, 5, 2],
  5198. mask=False,
  5199. fill_value=999999)
  5200. >>> x.ptp()
  5201. 10
  5202. This example shows that a negative value can be returned when
  5203. the input is an array of signed integers.
  5204. >>> y = np.ma.MaskedArray([[1, 127],
  5205. ... [0, 127],
  5206. ... [-1, 127],
  5207. ... [-2, 127]], dtype=np.int8)
  5208. >>> y.ptp(axis=1)
  5209. masked_array(data=[ 126, 127, -128, -127],
  5210. mask=False,
  5211. fill_value=np.int64(999999),
  5212. dtype=int8)
  5213. A work-around is to use the `view()` method to view the result as
  5214. unsigned integers with the same bit width:
  5215. >>> y.ptp(axis=1).view(np.uint8)
  5216. masked_array(data=[126, 127, 128, 129],
  5217. mask=False,
  5218. fill_value=np.uint64(999999),
  5219. dtype=uint8)
  5220. """
  5221. if out is None:
  5222. result = self.max(axis=axis, fill_value=fill_value,
  5223. keepdims=keepdims)
  5224. result -= self.min(axis=axis, fill_value=fill_value,
  5225. keepdims=keepdims)
  5226. return result
  5227. out.flat = self.max(axis=axis, out=out, fill_value=fill_value,
  5228. keepdims=keepdims)
  5229. min_value = self.min(axis=axis, fill_value=fill_value,
  5230. keepdims=keepdims)
  5231. np.subtract(out, min_value, out=out, casting='unsafe')
  5232. return out
  5233. def partition(self, *args, **kwargs):
  5234. warnings.warn("Warning: 'partition' will ignore the 'mask' "
  5235. f"of the {self.__class__.__name__}.",
  5236. stacklevel=2)
  5237. return super().partition(*args, **kwargs)
  5238. def argpartition(self, *args, **kwargs):
  5239. warnings.warn("Warning: 'argpartition' will ignore the 'mask' "
  5240. f"of the {self.__class__.__name__}.",
  5241. stacklevel=2)
  5242. return super().argpartition(*args, **kwargs)
  5243. def take(self, indices, axis=None, out=None, mode='raise'):
  5244. """
  5245. Take elements from a masked array along an axis.
  5246. This function does the same thing as "fancy" indexing (indexing arrays
  5247. using arrays) for masked arrays. It can be easier to use if you need
  5248. elements along a given axis.
  5249. Parameters
  5250. ----------
  5251. a : masked_array
  5252. The source masked array.
  5253. indices : array_like
  5254. The indices of the values to extract. Also allow scalars for indices.
  5255. axis : int, optional
  5256. The axis over which to select values. By default, the flattened
  5257. input array is used.
  5258. out : MaskedArray, optional
  5259. If provided, the result will be placed in this array. It should
  5260. be of the appropriate shape and dtype. Note that `out` is always
  5261. buffered if `mode='raise'`; use other modes for better performance.
  5262. mode : {'raise', 'wrap', 'clip'}, optional
  5263. Specifies how out-of-bounds indices will behave.
  5264. * 'raise' -- raise an error (default)
  5265. * 'wrap' -- wrap around
  5266. * 'clip' -- clip to the range
  5267. 'clip' mode means that all indices that are too large are replaced
  5268. by the index that addresses the last element along that axis. Note
  5269. that this disables indexing with negative numbers.
  5270. Returns
  5271. -------
  5272. out : MaskedArray
  5273. The returned array has the same type as `a`.
  5274. See Also
  5275. --------
  5276. numpy.take : Equivalent function for ndarrays.
  5277. compress : Take elements using a boolean mask.
  5278. take_along_axis : Take elements by matching the array and the index arrays.
  5279. Notes
  5280. -----
  5281. This function behaves similarly to `numpy.take`, but it handles masked
  5282. values. The mask is retained in the output array, and masked values
  5283. in the input array remain masked in the output.
  5284. Examples
  5285. --------
  5286. >>> import numpy as np
  5287. >>> a = np.ma.array([4, 3, 5, 7, 6, 8], mask=[0, 0, 1, 0, 1, 0])
  5288. >>> indices = [0, 1, 4]
  5289. >>> np.ma.take(a, indices)
  5290. masked_array(data=[4, 3, --],
  5291. mask=[False, False, True],
  5292. fill_value=999999)
  5293. When `indices` is not one-dimensional, the output also has these dimensions:
  5294. >>> np.ma.take(a, [[0, 1], [2, 3]])
  5295. masked_array(data=[[4, 3],
  5296. [--, 7]],
  5297. mask=[[False, False],
  5298. [ True, False]],
  5299. fill_value=999999)
  5300. """
  5301. (_data, _mask) = (self._data, self._mask)
  5302. cls = type(self)
  5303. # Make sure the indices are not masked
  5304. maskindices = getmask(indices)
  5305. if maskindices is not nomask:
  5306. indices = indices.filled(0)
  5307. # Get the data, promoting scalars to 0d arrays with [...] so that
  5308. # .view works correctly
  5309. if out is None:
  5310. out = _data.take(indices, axis=axis, mode=mode)[...].view(cls)
  5311. else:
  5312. np.take(_data, indices, axis=axis, mode=mode, out=out)
  5313. # Get the mask
  5314. if isinstance(out, MaskedArray):
  5315. if _mask is nomask:
  5316. outmask = maskindices
  5317. else:
  5318. outmask = _mask.take(indices, axis=axis, mode=mode)
  5319. outmask |= maskindices
  5320. out.__setmask__(outmask)
  5321. # demote 0d arrays back to scalars, for consistency with ndarray.take
  5322. return out[()]
  5323. # Array methods
  5324. copy = _arraymethod('copy')
  5325. diagonal = _arraymethod('diagonal')
  5326. flatten = _arraymethod('flatten')
  5327. repeat = _arraymethod('repeat')
  5328. squeeze = _arraymethod('squeeze')
  5329. swapaxes = _arraymethod('swapaxes')
  5330. T = property(fget=lambda self: self.transpose())
  5331. transpose = _arraymethod('transpose')
  5332. @property
  5333. def mT(self):
  5334. """
  5335. Return the matrix-transpose of the masked array.
  5336. The matrix transpose is the transpose of the last two dimensions, even
  5337. if the array is of higher dimension.
  5338. .. versionadded:: 2.0
  5339. Returns
  5340. -------
  5341. result: MaskedArray
  5342. The masked array with the last two dimensions transposed
  5343. Raises
  5344. ------
  5345. ValueError
  5346. If the array is of dimension less than 2.
  5347. See Also
  5348. --------
  5349. ndarray.mT:
  5350. Equivalent method for arrays
  5351. """
  5352. if self.ndim < 2:
  5353. raise ValueError("matrix transpose with ndim < 2 is undefined")
  5354. if self._mask is nomask:
  5355. return masked_array(data=self._data.mT)
  5356. else:
  5357. return masked_array(data=self.data.mT, mask=self.mask.mT)
  5358. def tolist(self, fill_value=None):
  5359. """
  5360. Return the data portion of the masked array as a hierarchical Python list.
  5361. Data items are converted to the nearest compatible Python type.
  5362. Masked values are converted to `fill_value`. If `fill_value` is None,
  5363. the corresponding entries in the output list will be ``None``.
  5364. Parameters
  5365. ----------
  5366. fill_value : scalar, optional
  5367. The value to use for invalid entries. Default is None.
  5368. Returns
  5369. -------
  5370. result : list
  5371. The Python list representation of the masked array.
  5372. Examples
  5373. --------
  5374. >>> import numpy as np
  5375. >>> x = np.ma.array([[1,2,3], [4,5,6], [7,8,9]], mask=[0] + [1,0]*4)
  5376. >>> x.tolist()
  5377. [[1, None, 3], [None, 5, None], [7, None, 9]]
  5378. >>> x.tolist(-999)
  5379. [[1, -999, 3], [-999, 5, -999], [7, -999, 9]]
  5380. """
  5381. _mask = self._mask
  5382. # No mask ? Just return .data.tolist ?
  5383. if _mask is nomask:
  5384. return self._data.tolist()
  5385. # Explicit fill_value: fill the array and get the list
  5386. if fill_value is not None:
  5387. return self.filled(fill_value).tolist()
  5388. # Structured array.
  5389. names = self.dtype.names
  5390. if names:
  5391. result = self._data.astype([(_, object) for _ in names])
  5392. for n in names:
  5393. result[n][_mask[n]] = None
  5394. return result.tolist()
  5395. # Standard arrays.
  5396. if _mask is nomask:
  5397. return [None]
  5398. # Set temps to save time when dealing w/ marrays.
  5399. inishape = self.shape
  5400. result = np.array(self._data.ravel(), dtype=object)
  5401. result[_mask.ravel()] = None
  5402. result.shape = inishape
  5403. return result.tolist()
  5404. def tostring(self, fill_value=None, order='C'):
  5405. r"""
  5406. A compatibility alias for `tobytes`, with exactly the same behavior.
  5407. Despite its name, it returns `bytes` not `str`\ s.
  5408. .. deprecated:: 1.19.0
  5409. """
  5410. # 2020-03-30, Numpy 1.19.0
  5411. warnings.warn(
  5412. "tostring() is deprecated. Use tobytes() instead.",
  5413. DeprecationWarning, stacklevel=2)
  5414. return self.tobytes(fill_value, order=order)
  5415. def tobytes(self, fill_value=None, order='C'):
  5416. """
  5417. Return the array data as a string containing the raw bytes in the array.
  5418. The array is filled with a fill value before the string conversion.
  5419. Parameters
  5420. ----------
  5421. fill_value : scalar, optional
  5422. Value used to fill in the masked values. Default is None, in which
  5423. case `MaskedArray.fill_value` is used.
  5424. order : {'C','F','A'}, optional
  5425. Order of the data item in the copy. Default is 'C'.
  5426. - 'C' -- C order (row major).
  5427. - 'F' -- Fortran order (column major).
  5428. - 'A' -- Any, current order of array.
  5429. - None -- Same as 'A'.
  5430. See Also
  5431. --------
  5432. numpy.ndarray.tobytes
  5433. tolist, tofile
  5434. Notes
  5435. -----
  5436. As for `ndarray.tobytes`, information about the shape, dtype, etc.,
  5437. but also about `fill_value`, will be lost.
  5438. Examples
  5439. --------
  5440. >>> import numpy as np
  5441. >>> x = np.ma.array(np.array([[1, 2], [3, 4]]), mask=[[0, 1], [1, 0]])
  5442. >>> x.tobytes()
  5443. b'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00?B\\x0f\\x00\\x00\\x00\\x00\\x00?B\\x0f\\x00\\x00\\x00\\x00\\x00\\x04\\x00\\x00\\x00\\x00\\x00\\x00\\x00'
  5444. """
  5445. return self.filled(fill_value).tobytes(order=order)
  5446. def tofile(self, fid, sep="", format="%s"):
  5447. """
  5448. Save a masked array to a file in binary format.
  5449. .. warning::
  5450. This function is not implemented yet.
  5451. Raises
  5452. ------
  5453. NotImplementedError
  5454. When `tofile` is called.
  5455. """
  5456. raise NotImplementedError("MaskedArray.tofile() not implemented yet.")
  5457. def toflex(self):
  5458. """
  5459. Transforms a masked array into a flexible-type array.
  5460. The flexible type array that is returned will have two fields:
  5461. * the ``_data`` field stores the ``_data`` part of the array.
  5462. * the ``_mask`` field stores the ``_mask`` part of the array.
  5463. Parameters
  5464. ----------
  5465. None
  5466. Returns
  5467. -------
  5468. record : ndarray
  5469. A new flexible-type `ndarray` with two fields: the first element
  5470. containing a value, the second element containing the corresponding
  5471. mask boolean. The returned record shape matches self.shape.
  5472. Notes
  5473. -----
  5474. A side-effect of transforming a masked array into a flexible `ndarray` is
  5475. that meta information (``fill_value``, ...) will be lost.
  5476. Examples
  5477. --------
  5478. >>> import numpy as np
  5479. >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4)
  5480. >>> x
  5481. masked_array(
  5482. data=[[1, --, 3],
  5483. [--, 5, --],
  5484. [7, --, 9]],
  5485. mask=[[False, True, False],
  5486. [ True, False, True],
  5487. [False, True, False]],
  5488. fill_value=999999)
  5489. >>> x.toflex()
  5490. array([[(1, False), (2, True), (3, False)],
  5491. [(4, True), (5, False), (6, True)],
  5492. [(7, False), (8, True), (9, False)]],
  5493. dtype=[('_data', '<i8'), ('_mask', '?')])
  5494. """
  5495. # Get the basic dtype.
  5496. ddtype = self.dtype
  5497. # Make sure we have a mask
  5498. _mask = self._mask
  5499. if _mask is None:
  5500. _mask = make_mask_none(self.shape, ddtype)
  5501. # And get its dtype
  5502. mdtype = self._mask.dtype
  5503. record = np.ndarray(shape=self.shape,
  5504. dtype=[('_data', ddtype), ('_mask', mdtype)])
  5505. record['_data'] = self._data
  5506. record['_mask'] = self._mask
  5507. return record
  5508. torecords = toflex
  5509. # Pickling
  5510. def __getstate__(self):
  5511. """Return the internal state of the masked array, for pickling
  5512. purposes.
  5513. """
  5514. cf = 'CF'[self.flags.fnc]
  5515. data_state = super().__reduce__()[2]
  5516. return data_state + (getmaskarray(self).tobytes(cf), self._fill_value)
  5517. def __setstate__(self, state):
  5518. """Restore the internal state of the masked array, for
  5519. pickling purposes. ``state`` is typically the output of the
  5520. ``__getstate__`` output, and is a 5-tuple:
  5521. - class name
  5522. - a tuple giving the shape of the data
  5523. - a typecode for the data
  5524. - a binary string for the data
  5525. - a binary string for the mask.
  5526. """
  5527. (_, shp, typ, isf, raw, msk, flv) = state
  5528. super().__setstate__((shp, typ, isf, raw))
  5529. self._mask.__setstate__((shp, make_mask_descr(typ), isf, msk))
  5530. self.fill_value = flv
  5531. def __reduce__(self):
  5532. """Return a 3-tuple for pickling a MaskedArray.
  5533. """
  5534. return (_mareconstruct,
  5535. (self.__class__, self._baseclass, (0,), 'b',),
  5536. self.__getstate__())
  5537. def __deepcopy__(self, memo=None):
  5538. from copy import deepcopy
  5539. copied = MaskedArray.__new__(type(self), self, copy=True)
  5540. if memo is None:
  5541. memo = {}
  5542. memo[id(self)] = copied
  5543. for (k, v) in self.__dict__.items():
  5544. copied.__dict__[k] = deepcopy(v, memo)
  5545. # as clearly documented for np.copy(), you need to use
  5546. # deepcopy() directly for arrays of object type that may
  5547. # contain compound types--you cannot depend on normal
  5548. # copy semantics to do the right thing here
  5549. if self.dtype.hasobject:
  5550. copied._data[...] = deepcopy(copied._data)
  5551. return copied
  5552. def _mareconstruct(subtype, baseclass, baseshape, basetype,):
  5553. """Internal function that builds a new MaskedArray from the
  5554. information stored in a pickle.
  5555. """
  5556. _data = ndarray.__new__(baseclass, baseshape, basetype)
  5557. _mask = ndarray.__new__(ndarray, baseshape, make_mask_descr(basetype))
  5558. return subtype.__new__(subtype, _data, mask=_mask, dtype=basetype,)
  5559. class mvoid(MaskedArray):
  5560. """
  5561. Fake a 'void' object to use for masked array with structured dtypes.
  5562. """
  5563. def __new__(self, data, mask=nomask, dtype=None, fill_value=None,
  5564. hardmask=False, copy=False, subok=True):
  5565. copy = None if not copy else True
  5566. _data = np.array(data, copy=copy, subok=subok, dtype=dtype)
  5567. _data = _data.view(self)
  5568. _data._hardmask = hardmask
  5569. if mask is not nomask:
  5570. if isinstance(mask, np.void):
  5571. _data._mask = mask
  5572. else:
  5573. try:
  5574. # Mask is already a 0D array
  5575. _data._mask = np.void(mask)
  5576. except TypeError:
  5577. # Transform the mask to a void
  5578. mdtype = make_mask_descr(dtype)
  5579. _data._mask = np.array(mask, dtype=mdtype)[()]
  5580. if fill_value is not None:
  5581. _data.fill_value = fill_value
  5582. return _data
  5583. @property
  5584. def _data(self):
  5585. # Make sure that the _data part is a np.void
  5586. return super()._data[()]
  5587. def __getitem__(self, indx):
  5588. """
  5589. Get the index.
  5590. """
  5591. m = self._mask
  5592. if isinstance(m[indx], ndarray):
  5593. # Can happen when indx is a multi-dimensional field:
  5594. # A = ma.masked_array(data=[([0,1],)], mask=[([True,
  5595. # False],)], dtype=[("A", ">i2", (2,))])
  5596. # x = A[0]; y = x["A"]; then y.mask["A"].size==2
  5597. # and we can not say masked/unmasked.
  5598. # The result is no longer mvoid!
  5599. # See also issue #6724.
  5600. return masked_array(
  5601. data=self._data[indx], mask=m[indx],
  5602. fill_value=self._fill_value[indx],
  5603. hard_mask=self._hardmask)
  5604. if m is not nomask and m[indx]:
  5605. return masked
  5606. return self._data[indx]
  5607. def __setitem__(self, indx, value):
  5608. self._data[indx] = value
  5609. if self._hardmask:
  5610. self._mask[indx] |= getattr(value, "_mask", False)
  5611. else:
  5612. self._mask[indx] = getattr(value, "_mask", False)
  5613. def __str__(self):
  5614. m = self._mask
  5615. if m is nomask:
  5616. return str(self._data)
  5617. rdtype = _replace_dtype_fields(self._data.dtype, "O")
  5618. data_arr = super()._data
  5619. res = data_arr.astype(rdtype)
  5620. _recursive_printoption(res, self._mask, masked_print_option)
  5621. return str(res)
  5622. __repr__ = __str__
  5623. def __iter__(self):
  5624. "Defines an iterator for mvoid"
  5625. (_data, _mask) = (self._data, self._mask)
  5626. if _mask is nomask:
  5627. yield from _data
  5628. else:
  5629. for (d, m) in zip(_data, _mask):
  5630. if m:
  5631. yield masked
  5632. else:
  5633. yield d
  5634. def __len__(self):
  5635. return self._data.__len__()
  5636. def filled(self, fill_value=None):
  5637. """
  5638. Return a copy with masked fields filled with a given value.
  5639. Parameters
  5640. ----------
  5641. fill_value : array_like, optional
  5642. The value to use for invalid entries. Can be scalar or
  5643. non-scalar. If latter is the case, the filled array should
  5644. be broadcastable over input array. Default is None, in
  5645. which case the `fill_value` attribute is used instead.
  5646. Returns
  5647. -------
  5648. filled_void
  5649. A `np.void` object
  5650. See Also
  5651. --------
  5652. MaskedArray.filled
  5653. """
  5654. return asarray(self).filled(fill_value)[()]
  5655. def tolist(self):
  5656. """
  5657. Transforms the mvoid object into a tuple.
  5658. Masked fields are replaced by None.
  5659. Returns
  5660. -------
  5661. returned_tuple
  5662. Tuple of fields
  5663. """
  5664. _mask = self._mask
  5665. if _mask is nomask:
  5666. return self._data.tolist()
  5667. result = []
  5668. for (d, m) in zip(self._data, self._mask):
  5669. if m:
  5670. result.append(None)
  5671. else:
  5672. # .item() makes sure we return a standard Python object
  5673. result.append(d.item())
  5674. return tuple(result)
  5675. ##############################################################################
  5676. # Shortcuts #
  5677. ##############################################################################
  5678. def isMaskedArray(x):
  5679. """
  5680. Test whether input is an instance of MaskedArray.
  5681. This function returns True if `x` is an instance of MaskedArray
  5682. and returns False otherwise. Any object is accepted as input.
  5683. Parameters
  5684. ----------
  5685. x : object
  5686. Object to test.
  5687. Returns
  5688. -------
  5689. result : bool
  5690. True if `x` is a MaskedArray.
  5691. See Also
  5692. --------
  5693. isMA : Alias to isMaskedArray.
  5694. isarray : Alias to isMaskedArray.
  5695. Examples
  5696. --------
  5697. >>> import numpy as np
  5698. >>> import numpy.ma as ma
  5699. >>> a = np.eye(3, 3)
  5700. >>> a
  5701. array([[ 1., 0., 0.],
  5702. [ 0., 1., 0.],
  5703. [ 0., 0., 1.]])
  5704. >>> m = ma.masked_values(a, 0)
  5705. >>> m
  5706. masked_array(
  5707. data=[[1.0, --, --],
  5708. [--, 1.0, --],
  5709. [--, --, 1.0]],
  5710. mask=[[False, True, True],
  5711. [ True, False, True],
  5712. [ True, True, False]],
  5713. fill_value=0.0)
  5714. >>> ma.isMaskedArray(a)
  5715. False
  5716. >>> ma.isMaskedArray(m)
  5717. True
  5718. >>> ma.isMaskedArray([0, 1, 2])
  5719. False
  5720. """
  5721. return isinstance(x, MaskedArray)
  5722. isarray = isMaskedArray
  5723. isMA = isMaskedArray # backward compatibility
  5724. class MaskedConstant(MaskedArray):
  5725. # the lone np.ma.masked instance
  5726. __singleton = None
  5727. @classmethod
  5728. def __has_singleton(cls):
  5729. # second case ensures `cls.__singleton` is not just a view on the
  5730. # superclass singleton
  5731. return cls.__singleton is not None and type(cls.__singleton) is cls
  5732. def __new__(cls):
  5733. if not cls.__has_singleton():
  5734. # We define the masked singleton as a float for higher precedence.
  5735. # Note that it can be tricky sometimes w/ type comparison
  5736. data = np.array(0.)
  5737. mask = np.array(True)
  5738. # prevent any modifications
  5739. data.flags.writeable = False
  5740. mask.flags.writeable = False
  5741. # don't fall back on MaskedArray.__new__(MaskedConstant), since
  5742. # that might confuse it - this way, the construction is entirely
  5743. # within our control
  5744. cls.__singleton = MaskedArray(data, mask=mask).view(cls)
  5745. return cls.__singleton
  5746. def __array_finalize__(self, obj):
  5747. if not self.__has_singleton():
  5748. # this handles the `.view` in __new__, which we want to copy across
  5749. # properties normally
  5750. return super().__array_finalize__(obj)
  5751. elif self is self.__singleton:
  5752. # not clear how this can happen, play it safe
  5753. pass
  5754. else:
  5755. # everywhere else, we want to downcast to MaskedArray, to prevent a
  5756. # duplicate maskedconstant.
  5757. self.__class__ = MaskedArray
  5758. MaskedArray.__array_finalize__(self, obj)
  5759. def __array_wrap__(self, obj, context=None, return_scalar=False):
  5760. return self.view(MaskedArray).__array_wrap__(obj, context)
  5761. def __str__(self):
  5762. return str(masked_print_option._display)
  5763. def __repr__(self):
  5764. if self is MaskedConstant.__singleton:
  5765. return 'masked'
  5766. else:
  5767. # it's a subclass, or something is wrong, make it obvious
  5768. return object.__repr__(self)
  5769. def __format__(self, format_spec):
  5770. # Replace ndarray.__format__ with the default, which supports no format characters.
  5771. # Supporting format characters is unwise here, because we do not know what type
  5772. # the user was expecting - better to not guess.
  5773. try:
  5774. return object.__format__(self, format_spec)
  5775. except TypeError:
  5776. # 2020-03-23, NumPy 1.19.0
  5777. warnings.warn(
  5778. "Format strings passed to MaskedConstant are ignored, but in future may "
  5779. "error or produce different behavior",
  5780. FutureWarning, stacklevel=2
  5781. )
  5782. return object.__format__(self, "")
  5783. def __reduce__(self):
  5784. """Override of MaskedArray's __reduce__.
  5785. """
  5786. return (self.__class__, ())
  5787. # inplace operations have no effect. We have to override them to avoid
  5788. # trying to modify the readonly data and mask arrays
  5789. def __iop__(self, other):
  5790. return self
  5791. __iadd__ = \
  5792. __isub__ = \
  5793. __imul__ = \
  5794. __ifloordiv__ = \
  5795. __itruediv__ = \
  5796. __ipow__ = \
  5797. __iop__
  5798. del __iop__ # don't leave this around
  5799. def copy(self, *args, **kwargs):
  5800. """ Copy is a no-op on the maskedconstant, as it is a scalar """
  5801. # maskedconstant is a scalar, so copy doesn't need to copy. There's
  5802. # precedent for this with `np.bool` scalars.
  5803. return self
  5804. def __copy__(self):
  5805. return self
  5806. def __deepcopy__(self, memo):
  5807. return self
  5808. def __setattr__(self, attr, value):
  5809. if not self.__has_singleton():
  5810. # allow the singleton to be initialized
  5811. return super().__setattr__(attr, value)
  5812. elif self is self.__singleton:
  5813. raise AttributeError(
  5814. f"attributes of {self!r} are not writeable")
  5815. else:
  5816. # duplicate instance - we can end up here from __array_finalize__,
  5817. # where we set the __class__ attribute
  5818. return super().__setattr__(attr, value)
  5819. masked = masked_singleton = MaskedConstant()
  5820. masked_array = MaskedArray
  5821. def array(data, dtype=None, copy=False, order=None,
  5822. mask=nomask, fill_value=None, keep_mask=True,
  5823. hard_mask=False, shrink=True, subok=True, ndmin=0):
  5824. """
  5825. Shortcut to MaskedArray.
  5826. The options are in a different order for convenience and backwards
  5827. compatibility.
  5828. """
  5829. return MaskedArray(data, mask=mask, dtype=dtype, copy=copy,
  5830. subok=subok, keep_mask=keep_mask,
  5831. hard_mask=hard_mask, fill_value=fill_value,
  5832. ndmin=ndmin, shrink=shrink, order=order)
  5833. array.__doc__ = masked_array.__doc__
  5834. def is_masked(x):
  5835. """
  5836. Determine whether input has masked values.
  5837. Accepts any object as input, but always returns False unless the
  5838. input is a MaskedArray containing masked values.
  5839. Parameters
  5840. ----------
  5841. x : array_like
  5842. Array to check for masked values.
  5843. Returns
  5844. -------
  5845. result : bool
  5846. True if `x` is a MaskedArray with masked values, False otherwise.
  5847. Examples
  5848. --------
  5849. >>> import numpy as np
  5850. >>> import numpy.ma as ma
  5851. >>> x = ma.masked_equal([0, 1, 0, 2, 3], 0)
  5852. >>> x
  5853. masked_array(data=[--, 1, --, 2, 3],
  5854. mask=[ True, False, True, False, False],
  5855. fill_value=0)
  5856. >>> ma.is_masked(x)
  5857. True
  5858. >>> x = ma.masked_equal([0, 1, 0, 2, 3], 42)
  5859. >>> x
  5860. masked_array(data=[0, 1, 0, 2, 3],
  5861. mask=False,
  5862. fill_value=42)
  5863. >>> ma.is_masked(x)
  5864. False
  5865. Always returns False if `x` isn't a MaskedArray.
  5866. >>> x = [False, True, False]
  5867. >>> ma.is_masked(x)
  5868. False
  5869. >>> x = 'a string'
  5870. >>> ma.is_masked(x)
  5871. False
  5872. """
  5873. m = getmask(x)
  5874. if m is nomask:
  5875. return False
  5876. elif m.any():
  5877. return True
  5878. return False
  5879. ##############################################################################
  5880. # Extrema functions #
  5881. ##############################################################################
  5882. class _extrema_operation(_MaskedUFunc):
  5883. """
  5884. Generic class for maximum/minimum functions.
  5885. .. note::
  5886. This is the base class for `_maximum_operation` and
  5887. `_minimum_operation`.
  5888. """
  5889. def __init__(self, ufunc, compare, fill_value):
  5890. super().__init__(ufunc)
  5891. self.compare = compare
  5892. self.fill_value_func = fill_value
  5893. def __call__(self, a, b):
  5894. "Executes the call behavior."
  5895. return where(self.compare(a, b), a, b)
  5896. def reduce(self, target, axis=np._NoValue):
  5897. "Reduce target along the given axis."
  5898. target = narray(target, copy=None, subok=True)
  5899. m = getmask(target)
  5900. if axis is np._NoValue and target.ndim > 1:
  5901. # 2017-05-06, Numpy 1.13.0: warn on axis default
  5902. warnings.warn(
  5903. f"In the future the default for ma.{self.__name__}.reduce will be axis=0, "
  5904. f"not the current None, to match np.{self.__name__}.reduce. "
  5905. "Explicitly pass 0 or None to silence this warning.",
  5906. MaskedArrayFutureWarning, stacklevel=2)
  5907. axis = None
  5908. if axis is not np._NoValue:
  5909. kwargs = dict(axis=axis)
  5910. else:
  5911. kwargs = dict()
  5912. if m is nomask:
  5913. t = self.f.reduce(target, **kwargs)
  5914. else:
  5915. target = target.filled(
  5916. self.fill_value_func(target)).view(type(target))
  5917. t = self.f.reduce(target, **kwargs)
  5918. m = umath.logical_and.reduce(m, **kwargs)
  5919. if hasattr(t, '_mask'):
  5920. t._mask = m
  5921. elif m:
  5922. t = masked
  5923. return t
  5924. def outer(self, a, b):
  5925. "Return the function applied to the outer product of a and b."
  5926. ma = getmask(a)
  5927. mb = getmask(b)
  5928. if ma is nomask and mb is nomask:
  5929. m = nomask
  5930. else:
  5931. ma = getmaskarray(a)
  5932. mb = getmaskarray(b)
  5933. m = logical_or.outer(ma, mb)
  5934. result = self.f.outer(filled(a), filled(b))
  5935. if not isinstance(result, MaskedArray):
  5936. result = result.view(MaskedArray)
  5937. result._mask = m
  5938. return result
  5939. def min(obj, axis=None, out=None, fill_value=None, keepdims=np._NoValue):
  5940. kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
  5941. try:
  5942. return obj.min(axis=axis, fill_value=fill_value, out=out, **kwargs)
  5943. except (AttributeError, TypeError):
  5944. # If obj doesn't have a min method, or if the method doesn't accept a
  5945. # fill_value argument
  5946. return asanyarray(obj).min(axis=axis, fill_value=fill_value,
  5947. out=out, **kwargs)
  5948. min.__doc__ = MaskedArray.min.__doc__
  5949. def max(obj, axis=None, out=None, fill_value=None, keepdims=np._NoValue):
  5950. kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
  5951. try:
  5952. return obj.max(axis=axis, fill_value=fill_value, out=out, **kwargs)
  5953. except (AttributeError, TypeError):
  5954. # If obj doesn't have a max method, or if the method doesn't accept a
  5955. # fill_value argument
  5956. return asanyarray(obj).max(axis=axis, fill_value=fill_value,
  5957. out=out, **kwargs)
  5958. max.__doc__ = MaskedArray.max.__doc__
  5959. def ptp(obj, axis=None, out=None, fill_value=None, keepdims=np._NoValue):
  5960. kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
  5961. try:
  5962. return obj.ptp(axis, out=out, fill_value=fill_value, **kwargs)
  5963. except (AttributeError, TypeError):
  5964. # If obj doesn't have a ptp method or if the method doesn't accept
  5965. # a fill_value argument
  5966. return asanyarray(obj).ptp(axis=axis, fill_value=fill_value,
  5967. out=out, **kwargs)
  5968. ptp.__doc__ = MaskedArray.ptp.__doc__
  5969. ##############################################################################
  5970. # Definition of functions from the corresponding methods #
  5971. ##############################################################################
  5972. class _frommethod:
  5973. """
  5974. Define functions from existing MaskedArray methods.
  5975. Parameters
  5976. ----------
  5977. methodname : str
  5978. Name of the method to transform.
  5979. """
  5980. def __init__(self, methodname, reversed=False):
  5981. self.__name__ = methodname
  5982. self.__qualname__ = methodname
  5983. self.__doc__ = self.getdoc()
  5984. self.reversed = reversed
  5985. def getdoc(self):
  5986. "Return the doc of the function (from the doc of the method)."
  5987. meth = getattr(MaskedArray, self.__name__, None) or\
  5988. getattr(np, self.__name__, None)
  5989. signature = self.__name__ + get_object_signature(meth)
  5990. if meth is not None:
  5991. doc = """ %s\n%s""" % (
  5992. signature, getattr(meth, '__doc__', None))
  5993. return doc
  5994. def __call__(self, a, *args, **params):
  5995. if self.reversed:
  5996. args = list(args)
  5997. a, args[0] = args[0], a
  5998. marr = asanyarray(a)
  5999. method_name = self.__name__
  6000. method = getattr(type(marr), method_name, None)
  6001. if method is None:
  6002. # use the corresponding np function
  6003. method = getattr(np, method_name)
  6004. return method(marr, *args, **params)
  6005. all = _frommethod('all')
  6006. anomalies = anom = _frommethod('anom')
  6007. any = _frommethod('any')
  6008. compress = _frommethod('compress', reversed=True)
  6009. cumprod = _frommethod('cumprod')
  6010. cumsum = _frommethod('cumsum')
  6011. copy = _frommethod('copy')
  6012. diagonal = _frommethod('diagonal')
  6013. harden_mask = _frommethod('harden_mask')
  6014. ids = _frommethod('ids')
  6015. maximum = _extrema_operation(umath.maximum, greater, maximum_fill_value)
  6016. mean = _frommethod('mean')
  6017. minimum = _extrema_operation(umath.minimum, less, minimum_fill_value)
  6018. nonzero = _frommethod('nonzero')
  6019. prod = _frommethod('prod')
  6020. product = _frommethod('prod')
  6021. ravel = _frommethod('ravel')
  6022. repeat = _frommethod('repeat')
  6023. shrink_mask = _frommethod('shrink_mask')
  6024. soften_mask = _frommethod('soften_mask')
  6025. std = _frommethod('std')
  6026. sum = _frommethod('sum')
  6027. swapaxes = _frommethod('swapaxes')
  6028. #take = _frommethod('take')
  6029. trace = _frommethod('trace')
  6030. var = _frommethod('var')
  6031. count = _frommethod('count')
  6032. def take(a, indices, axis=None, out=None, mode='raise'):
  6033. """
  6034. """
  6035. a = masked_array(a)
  6036. return a.take(indices, axis=axis, out=out, mode=mode)
  6037. def power(a, b, third=None):
  6038. """
  6039. Returns element-wise base array raised to power from second array.
  6040. This is the masked array version of `numpy.power`. For details see
  6041. `numpy.power`.
  6042. See Also
  6043. --------
  6044. numpy.power
  6045. Notes
  6046. -----
  6047. The *out* argument to `numpy.power` is not supported, `third` has to be
  6048. None.
  6049. Examples
  6050. --------
  6051. >>> import numpy as np
  6052. >>> import numpy.ma as ma
  6053. >>> x = [11.2, -3.973, 0.801, -1.41]
  6054. >>> mask = [0, 0, 0, 1]
  6055. >>> masked_x = ma.masked_array(x, mask)
  6056. >>> masked_x
  6057. masked_array(data=[11.2, -3.973, 0.801, --],
  6058. mask=[False, False, False, True],
  6059. fill_value=1e+20)
  6060. >>> ma.power(masked_x, 2)
  6061. masked_array(data=[125.43999999999998, 15.784728999999999,
  6062. 0.6416010000000001, --],
  6063. mask=[False, False, False, True],
  6064. fill_value=1e+20)
  6065. >>> y = [-0.5, 2, 0, 17]
  6066. >>> masked_y = ma.masked_array(y, mask)
  6067. >>> masked_y
  6068. masked_array(data=[-0.5, 2.0, 0.0, --],
  6069. mask=[False, False, False, True],
  6070. fill_value=1e+20)
  6071. >>> ma.power(masked_x, masked_y)
  6072. masked_array(data=[0.2988071523335984, 15.784728999999999, 1.0, --],
  6073. mask=[False, False, False, True],
  6074. fill_value=1e+20)
  6075. """
  6076. if third is not None:
  6077. raise MaskError("3-argument power not supported.")
  6078. # Get the masks
  6079. ma = getmask(a)
  6080. mb = getmask(b)
  6081. m = mask_or(ma, mb)
  6082. # Get the rawdata
  6083. fa = getdata(a)
  6084. fb = getdata(b)
  6085. # Get the type of the result (so that we preserve subclasses)
  6086. if isinstance(a, MaskedArray):
  6087. basetype = type(a)
  6088. else:
  6089. basetype = MaskedArray
  6090. # Get the result and view it as a (subclass of) MaskedArray
  6091. with np.errstate(divide='ignore', invalid='ignore'):
  6092. result = np.where(m, fa, umath.power(fa, fb)).view(basetype)
  6093. result._update_from(a)
  6094. # Find where we're in trouble w/ NaNs and Infs
  6095. invalid = np.logical_not(np.isfinite(result.view(ndarray)))
  6096. # Add the initial mask
  6097. if m is not nomask:
  6098. if not result.ndim:
  6099. return masked
  6100. result._mask = np.logical_or(m, invalid)
  6101. # Fix the invalid parts
  6102. if invalid.any():
  6103. if not result.ndim:
  6104. return masked
  6105. elif result._mask is nomask:
  6106. result._mask = invalid
  6107. result._data[invalid] = result.fill_value
  6108. return result
  6109. argmin = _frommethod('argmin')
  6110. argmax = _frommethod('argmax')
  6111. def argsort(a, axis=np._NoValue, kind=None, order=None, endwith=True,
  6112. fill_value=None, *, stable=None):
  6113. "Function version of the eponymous method."
  6114. a = np.asanyarray(a)
  6115. # 2017-04-11, Numpy 1.13.0, gh-8701: warn on axis default
  6116. if axis is np._NoValue:
  6117. axis = _deprecate_argsort_axis(a)
  6118. if isinstance(a, MaskedArray):
  6119. return a.argsort(axis=axis, kind=kind, order=order, endwith=endwith,
  6120. fill_value=fill_value, stable=None)
  6121. else:
  6122. return a.argsort(axis=axis, kind=kind, order=order, stable=None)
  6123. argsort.__doc__ = MaskedArray.argsort.__doc__
  6124. def sort(a, axis=-1, kind=None, order=None, endwith=True, fill_value=None, *,
  6125. stable=None):
  6126. """
  6127. Return a sorted copy of the masked array.
  6128. Equivalent to creating a copy of the array
  6129. and applying the MaskedArray ``sort()`` method.
  6130. Refer to ``MaskedArray.sort`` for the full documentation
  6131. See Also
  6132. --------
  6133. MaskedArray.sort : equivalent method
  6134. Examples
  6135. --------
  6136. >>> import numpy as np
  6137. >>> import numpy.ma as ma
  6138. >>> x = [11.2, -3.973, 0.801, -1.41]
  6139. >>> mask = [0, 0, 0, 1]
  6140. >>> masked_x = ma.masked_array(x, mask)
  6141. >>> masked_x
  6142. masked_array(data=[11.2, -3.973, 0.801, --],
  6143. mask=[False, False, False, True],
  6144. fill_value=1e+20)
  6145. >>> ma.sort(masked_x)
  6146. masked_array(data=[-3.973, 0.801, 11.2, --],
  6147. mask=[False, False, False, True],
  6148. fill_value=1e+20)
  6149. """
  6150. a = np.array(a, copy=True, subok=True)
  6151. if axis is None:
  6152. a = a.flatten()
  6153. axis = 0
  6154. if isinstance(a, MaskedArray):
  6155. a.sort(axis=axis, kind=kind, order=order, endwith=endwith,
  6156. fill_value=fill_value, stable=stable)
  6157. else:
  6158. a.sort(axis=axis, kind=kind, order=order, stable=stable)
  6159. return a
  6160. def compressed(x):
  6161. """
  6162. Return all the non-masked data as a 1-D array.
  6163. This function is equivalent to calling the "compressed" method of a
  6164. `ma.MaskedArray`, see `ma.MaskedArray.compressed` for details.
  6165. See Also
  6166. --------
  6167. ma.MaskedArray.compressed : Equivalent method.
  6168. Examples
  6169. --------
  6170. >>> import numpy as np
  6171. Create an array with negative values masked:
  6172. >>> import numpy as np
  6173. >>> x = np.array([[1, -1, 0], [2, -1, 3], [7, 4, -1]])
  6174. >>> masked_x = np.ma.masked_array(x, mask=x < 0)
  6175. >>> masked_x
  6176. masked_array(
  6177. data=[[1, --, 0],
  6178. [2, --, 3],
  6179. [7, 4, --]],
  6180. mask=[[False, True, False],
  6181. [False, True, False],
  6182. [False, False, True]],
  6183. fill_value=999999)
  6184. Compress the masked array into a 1-D array of non-masked values:
  6185. >>> np.ma.compressed(masked_x)
  6186. array([1, 0, 2, 3, 7, 4])
  6187. """
  6188. return asanyarray(x).compressed()
  6189. def concatenate(arrays, axis=0):
  6190. """
  6191. Concatenate a sequence of arrays along the given axis.
  6192. Parameters
  6193. ----------
  6194. arrays : sequence of array_like
  6195. The arrays must have the same shape, except in the dimension
  6196. corresponding to `axis` (the first, by default).
  6197. axis : int, optional
  6198. The axis along which the arrays will be joined. Default is 0.
  6199. Returns
  6200. -------
  6201. result : MaskedArray
  6202. The concatenated array with any masked entries preserved.
  6203. See Also
  6204. --------
  6205. numpy.concatenate : Equivalent function in the top-level NumPy module.
  6206. Examples
  6207. --------
  6208. >>> import numpy as np
  6209. >>> import numpy.ma as ma
  6210. >>> a = ma.arange(3)
  6211. >>> a[1] = ma.masked
  6212. >>> b = ma.arange(2, 5)
  6213. >>> a
  6214. masked_array(data=[0, --, 2],
  6215. mask=[False, True, False],
  6216. fill_value=999999)
  6217. >>> b
  6218. masked_array(data=[2, 3, 4],
  6219. mask=False,
  6220. fill_value=999999)
  6221. >>> ma.concatenate([a, b])
  6222. masked_array(data=[0, --, 2, 2, 3, 4],
  6223. mask=[False, True, False, False, False, False],
  6224. fill_value=999999)
  6225. """
  6226. d = np.concatenate([getdata(a) for a in arrays], axis)
  6227. rcls = get_masked_subclass(*arrays)
  6228. data = d.view(rcls)
  6229. # Check whether one of the arrays has a non-empty mask.
  6230. for x in arrays:
  6231. if getmask(x) is not nomask:
  6232. break
  6233. else:
  6234. return data
  6235. # OK, so we have to concatenate the masks
  6236. dm = np.concatenate([getmaskarray(a) for a in arrays], axis)
  6237. dm = dm.reshape(d.shape)
  6238. # If we decide to keep a '_shrinkmask' option, we want to check that
  6239. # all of them are True, and then check for dm.any()
  6240. data._mask = _shrink_mask(dm)
  6241. return data
  6242. def diag(v, k=0):
  6243. """
  6244. Extract a diagonal or construct a diagonal array.
  6245. This function is the equivalent of `numpy.diag` that takes masked
  6246. values into account, see `numpy.diag` for details.
  6247. See Also
  6248. --------
  6249. numpy.diag : Equivalent function for ndarrays.
  6250. Examples
  6251. --------
  6252. >>> import numpy as np
  6253. Create an array with negative values masked:
  6254. >>> import numpy as np
  6255. >>> x = np.array([[11.2, -3.973, 18], [0.801, -1.41, 12], [7, 33, -12]])
  6256. >>> masked_x = np.ma.masked_array(x, mask=x < 0)
  6257. >>> masked_x
  6258. masked_array(
  6259. data=[[11.2, --, 18.0],
  6260. [0.801, --, 12.0],
  6261. [7.0, 33.0, --]],
  6262. mask=[[False, True, False],
  6263. [False, True, False],
  6264. [False, False, True]],
  6265. fill_value=1e+20)
  6266. Isolate the main diagonal from the masked array:
  6267. >>> np.ma.diag(masked_x)
  6268. masked_array(data=[11.2, --, --],
  6269. mask=[False, True, True],
  6270. fill_value=1e+20)
  6271. Isolate the first diagonal below the main diagonal:
  6272. >>> np.ma.diag(masked_x, -1)
  6273. masked_array(data=[0.801, 33.0],
  6274. mask=[False, False],
  6275. fill_value=1e+20)
  6276. """
  6277. output = np.diag(v, k).view(MaskedArray)
  6278. if getmask(v) is not nomask:
  6279. output._mask = np.diag(v._mask, k)
  6280. return output
  6281. def left_shift(a, n):
  6282. """
  6283. Shift the bits of an integer to the left.
  6284. This is the masked array version of `numpy.left_shift`, for details
  6285. see that function.
  6286. See Also
  6287. --------
  6288. numpy.left_shift
  6289. Examples
  6290. --------
  6291. Shift with a masked array:
  6292. >>> arr = np.ma.array([10, 20, 30], mask=[False, True, False])
  6293. >>> np.ma.left_shift(arr, 1)
  6294. masked_array(data=[20, --, 60],
  6295. mask=[False, True, False],
  6296. fill_value=999999)
  6297. Large shift:
  6298. >>> np.ma.left_shift(10, 10)
  6299. masked_array(data=10240,
  6300. mask=False,
  6301. fill_value=999999)
  6302. Shift with a scalar and an array:
  6303. >>> scalar = 10
  6304. >>> arr = np.ma.array([1, 2, 3], mask=[False, True, False])
  6305. >>> np.ma.left_shift(scalar, arr)
  6306. masked_array(data=[20, --, 80],
  6307. mask=[False, True, False],
  6308. fill_value=999999)
  6309. """
  6310. m = getmask(a)
  6311. if m is nomask:
  6312. d = umath.left_shift(filled(a), n)
  6313. return masked_array(d)
  6314. else:
  6315. d = umath.left_shift(filled(a, 0), n)
  6316. return masked_array(d, mask=m)
  6317. def right_shift(a, n):
  6318. """
  6319. Shift the bits of an integer to the right.
  6320. This is the masked array version of `numpy.right_shift`, for details
  6321. see that function.
  6322. See Also
  6323. --------
  6324. numpy.right_shift
  6325. Examples
  6326. --------
  6327. >>> import numpy as np
  6328. >>> import numpy.ma as ma
  6329. >>> x = [11, 3, 8, 1]
  6330. >>> mask = [0, 0, 0, 1]
  6331. >>> masked_x = ma.masked_array(x, mask)
  6332. >>> masked_x
  6333. masked_array(data=[11, 3, 8, --],
  6334. mask=[False, False, False, True],
  6335. fill_value=999999)
  6336. >>> ma.right_shift(masked_x,1)
  6337. masked_array(data=[5, 1, 4, --],
  6338. mask=[False, False, False, True],
  6339. fill_value=999999)
  6340. """
  6341. m = getmask(a)
  6342. if m is nomask:
  6343. d = umath.right_shift(filled(a), n)
  6344. return masked_array(d)
  6345. else:
  6346. d = umath.right_shift(filled(a, 0), n)
  6347. return masked_array(d, mask=m)
  6348. def put(a, indices, values, mode='raise'):
  6349. """
  6350. Set storage-indexed locations to corresponding values.
  6351. This function is equivalent to `MaskedArray.put`, see that method
  6352. for details.
  6353. See Also
  6354. --------
  6355. MaskedArray.put
  6356. Examples
  6357. --------
  6358. Putting values in a masked array:
  6359. >>> a = np.ma.array([1, 2, 3, 4], mask=[False, True, False, False])
  6360. >>> np.ma.put(a, [1, 3], [10, 30])
  6361. >>> a
  6362. masked_array(data=[ 1, 10, 3, 30],
  6363. mask=False,
  6364. fill_value=999999)
  6365. Using put with a 2D array:
  6366. >>> b = np.ma.array([[1, 2], [3, 4]], mask=[[False, True], [False, False]])
  6367. >>> np.ma.put(b, [[0, 1], [1, 0]], [[10, 20], [30, 40]])
  6368. >>> b
  6369. masked_array(
  6370. data=[[40, 30],
  6371. [ 3, 4]],
  6372. mask=False,
  6373. fill_value=999999)
  6374. """
  6375. # We can't use 'frommethod', the order of arguments is different
  6376. try:
  6377. return a.put(indices, values, mode=mode)
  6378. except AttributeError:
  6379. return np.asarray(a).put(indices, values, mode=mode)
  6380. def putmask(a, mask, values): # , mode='raise'):
  6381. """
  6382. Changes elements of an array based on conditional and input values.
  6383. This is the masked array version of `numpy.putmask`, for details see
  6384. `numpy.putmask`.
  6385. See Also
  6386. --------
  6387. numpy.putmask
  6388. Notes
  6389. -----
  6390. Using a masked array as `values` will **not** transform a `ndarray` into
  6391. a `MaskedArray`.
  6392. Examples
  6393. --------
  6394. >>> import numpy as np
  6395. >>> arr = [[1, 2], [3, 4]]
  6396. >>> mask = [[1, 0], [0, 0]]
  6397. >>> x = np.ma.array(arr, mask=mask)
  6398. >>> np.ma.putmask(x, x < 4, 10*x)
  6399. >>> x
  6400. masked_array(
  6401. data=[[--, 20],
  6402. [30, 4]],
  6403. mask=[[ True, False],
  6404. [False, False]],
  6405. fill_value=999999)
  6406. >>> x.data
  6407. array([[10, 20],
  6408. [30, 4]])
  6409. """
  6410. # We can't use 'frommethod', the order of arguments is different
  6411. if not isinstance(a, MaskedArray):
  6412. a = a.view(MaskedArray)
  6413. (valdata, valmask) = (getdata(values), getmask(values))
  6414. if getmask(a) is nomask:
  6415. if valmask is not nomask:
  6416. a._sharedmask = True
  6417. a._mask = make_mask_none(a.shape, a.dtype)
  6418. np.copyto(a._mask, valmask, where=mask)
  6419. elif a._hardmask:
  6420. if valmask is not nomask:
  6421. m = a._mask.copy()
  6422. np.copyto(m, valmask, where=mask)
  6423. a.mask |= m
  6424. else:
  6425. if valmask is nomask:
  6426. valmask = getmaskarray(values)
  6427. np.copyto(a._mask, valmask, where=mask)
  6428. np.copyto(a._data, valdata, where=mask)
  6429. return
  6430. def transpose(a, axes=None):
  6431. """
  6432. Permute the dimensions of an array.
  6433. This function is exactly equivalent to `numpy.transpose`.
  6434. See Also
  6435. --------
  6436. numpy.transpose : Equivalent function in top-level NumPy module.
  6437. Examples
  6438. --------
  6439. >>> import numpy as np
  6440. >>> import numpy.ma as ma
  6441. >>> x = ma.arange(4).reshape((2,2))
  6442. >>> x[1, 1] = ma.masked
  6443. >>> x
  6444. masked_array(
  6445. data=[[0, 1],
  6446. [2, --]],
  6447. mask=[[False, False],
  6448. [False, True]],
  6449. fill_value=999999)
  6450. >>> ma.transpose(x)
  6451. masked_array(
  6452. data=[[0, 2],
  6453. [1, --]],
  6454. mask=[[False, False],
  6455. [False, True]],
  6456. fill_value=999999)
  6457. """
  6458. # We can't use 'frommethod', as 'transpose' doesn't take keywords
  6459. try:
  6460. return a.transpose(axes)
  6461. except AttributeError:
  6462. return np.asarray(a).transpose(axes).view(MaskedArray)
  6463. def reshape(a, new_shape, order='C'):
  6464. """
  6465. Returns an array containing the same data with a new shape.
  6466. Refer to `MaskedArray.reshape` for full documentation.
  6467. See Also
  6468. --------
  6469. MaskedArray.reshape : equivalent function
  6470. Examples
  6471. --------
  6472. Reshaping a 1-D array:
  6473. >>> a = np.ma.array([1, 2, 3, 4])
  6474. >>> np.ma.reshape(a, (2, 2))
  6475. masked_array(
  6476. data=[[1, 2],
  6477. [3, 4]],
  6478. mask=False,
  6479. fill_value=999999)
  6480. Reshaping a 2-D array:
  6481. >>> b = np.ma.array([[1, 2], [3, 4]])
  6482. >>> np.ma.reshape(b, (1, 4))
  6483. masked_array(data=[[1, 2, 3, 4]],
  6484. mask=False,
  6485. fill_value=999999)
  6486. Reshaping a 1-D array with a mask:
  6487. >>> c = np.ma.array([1, 2, 3, 4], mask=[False, True, False, False])
  6488. >>> np.ma.reshape(c, (2, 2))
  6489. masked_array(
  6490. data=[[1, --],
  6491. [3, 4]],
  6492. mask=[[False, True],
  6493. [False, False]],
  6494. fill_value=999999)
  6495. """
  6496. # We can't use 'frommethod', it whine about some parameters. Dmmit.
  6497. try:
  6498. return a.reshape(new_shape, order=order)
  6499. except AttributeError:
  6500. _tmp = np.asarray(a).reshape(new_shape, order=order)
  6501. return _tmp.view(MaskedArray)
  6502. def resize(x, new_shape):
  6503. """
  6504. Return a new masked array with the specified size and shape.
  6505. This is the masked equivalent of the `numpy.resize` function. The new
  6506. array is filled with repeated copies of `x` (in the order that the
  6507. data are stored in memory). If `x` is masked, the new array will be
  6508. masked, and the new mask will be a repetition of the old one.
  6509. See Also
  6510. --------
  6511. numpy.resize : Equivalent function in the top level NumPy module.
  6512. Examples
  6513. --------
  6514. >>> import numpy as np
  6515. >>> import numpy.ma as ma
  6516. >>> a = ma.array([[1, 2] ,[3, 4]])
  6517. >>> a[0, 1] = ma.masked
  6518. >>> a
  6519. masked_array(
  6520. data=[[1, --],
  6521. [3, 4]],
  6522. mask=[[False, True],
  6523. [False, False]],
  6524. fill_value=999999)
  6525. >>> np.resize(a, (3, 3))
  6526. masked_array(
  6527. data=[[1, 2, 3],
  6528. [4, 1, 2],
  6529. [3, 4, 1]],
  6530. mask=False,
  6531. fill_value=999999)
  6532. >>> ma.resize(a, (3, 3))
  6533. masked_array(
  6534. data=[[1, --, 3],
  6535. [4, 1, --],
  6536. [3, 4, 1]],
  6537. mask=[[False, True, False],
  6538. [False, False, True],
  6539. [False, False, False]],
  6540. fill_value=999999)
  6541. A MaskedArray is always returned, regardless of the input type.
  6542. >>> a = np.array([[1, 2] ,[3, 4]])
  6543. >>> ma.resize(a, (3, 3))
  6544. masked_array(
  6545. data=[[1, 2, 3],
  6546. [4, 1, 2],
  6547. [3, 4, 1]],
  6548. mask=False,
  6549. fill_value=999999)
  6550. """
  6551. # We can't use _frommethods here, as N.resize is notoriously whiny.
  6552. m = getmask(x)
  6553. if m is not nomask:
  6554. m = np.resize(m, new_shape)
  6555. result = np.resize(x, new_shape).view(get_masked_subclass(x))
  6556. if result.ndim:
  6557. result._mask = m
  6558. return result
  6559. def ndim(obj):
  6560. """
  6561. maskedarray version of the numpy function.
  6562. """
  6563. return np.ndim(getdata(obj))
  6564. ndim.__doc__ = np.ndim.__doc__
  6565. def shape(obj):
  6566. "maskedarray version of the numpy function."
  6567. return np.shape(getdata(obj))
  6568. shape.__doc__ = np.shape.__doc__
  6569. def size(obj, axis=None):
  6570. "maskedarray version of the numpy function."
  6571. return np.size(getdata(obj), axis)
  6572. size.__doc__ = np.size.__doc__
  6573. def diff(a, /, n=1, axis=-1, prepend=np._NoValue, append=np._NoValue):
  6574. """
  6575. Calculate the n-th discrete difference along the given axis.
  6576. The first difference is given by ``out[i] = a[i+1] - a[i]`` along
  6577. the given axis, higher differences are calculated by using `diff`
  6578. recursively.
  6579. Preserves the input mask.
  6580. Parameters
  6581. ----------
  6582. a : array_like
  6583. Input array
  6584. n : int, optional
  6585. The number of times values are differenced. If zero, the input
  6586. is returned as-is.
  6587. axis : int, optional
  6588. The axis along which the difference is taken, default is the
  6589. last axis.
  6590. prepend, append : array_like, optional
  6591. Values to prepend or append to `a` along axis prior to
  6592. performing the difference. Scalar values are expanded to
  6593. arrays with length 1 in the direction of axis and the shape
  6594. of the input array in along all other axes. Otherwise the
  6595. dimension and shape must match `a` except along axis.
  6596. Returns
  6597. -------
  6598. diff : MaskedArray
  6599. The n-th differences. The shape of the output is the same as `a`
  6600. except along `axis` where the dimension is smaller by `n`. The
  6601. type of the output is the same as the type of the difference
  6602. between any two elements of `a`. This is the same as the type of
  6603. `a` in most cases. A notable exception is `datetime64`, which
  6604. results in a `timedelta64` output array.
  6605. See Also
  6606. --------
  6607. numpy.diff : Equivalent function in the top-level NumPy module.
  6608. Notes
  6609. -----
  6610. Type is preserved for boolean arrays, so the result will contain
  6611. `False` when consecutive elements are the same and `True` when they
  6612. differ.
  6613. For unsigned integer arrays, the results will also be unsigned. This
  6614. should not be surprising, as the result is consistent with
  6615. calculating the difference directly:
  6616. >>> u8_arr = np.array([1, 0], dtype=np.uint8)
  6617. >>> np.ma.diff(u8_arr)
  6618. masked_array(data=[255],
  6619. mask=False,
  6620. fill_value=np.uint64(999999),
  6621. dtype=uint8)
  6622. >>> u8_arr[1,...] - u8_arr[0,...]
  6623. np.uint8(255)
  6624. If this is not desirable, then the array should be cast to a larger
  6625. integer type first:
  6626. >>> i16_arr = u8_arr.astype(np.int16)
  6627. >>> np.ma.diff(i16_arr)
  6628. masked_array(data=[-1],
  6629. mask=False,
  6630. fill_value=np.int64(999999),
  6631. dtype=int16)
  6632. Examples
  6633. --------
  6634. >>> import numpy as np
  6635. >>> a = np.array([1, 2, 3, 4, 7, 0, 2, 3])
  6636. >>> x = np.ma.masked_where(a < 2, a)
  6637. >>> np.ma.diff(x)
  6638. masked_array(data=[--, 1, 1, 3, --, --, 1],
  6639. mask=[ True, False, False, False, True, True, False],
  6640. fill_value=999999)
  6641. >>> np.ma.diff(x, n=2)
  6642. masked_array(data=[--, 0, 2, --, --, --],
  6643. mask=[ True, False, False, True, True, True],
  6644. fill_value=999999)
  6645. >>> a = np.array([[1, 3, 1, 5, 10], [0, 1, 5, 6, 8]])
  6646. >>> x = np.ma.masked_equal(a, value=1)
  6647. >>> np.ma.diff(x)
  6648. masked_array(
  6649. data=[[--, --, --, 5],
  6650. [--, --, 1, 2]],
  6651. mask=[[ True, True, True, False],
  6652. [ True, True, False, False]],
  6653. fill_value=1)
  6654. >>> np.ma.diff(x, axis=0)
  6655. masked_array(data=[[--, --, --, 1, -2]],
  6656. mask=[[ True, True, True, False, False]],
  6657. fill_value=1)
  6658. """
  6659. if n == 0:
  6660. return a
  6661. if n < 0:
  6662. raise ValueError("order must be non-negative but got " + repr(n))
  6663. a = np.ma.asanyarray(a)
  6664. if a.ndim == 0:
  6665. raise ValueError(
  6666. "diff requires input that is at least one dimensional"
  6667. )
  6668. combined = []
  6669. if prepend is not np._NoValue:
  6670. prepend = np.ma.asanyarray(prepend)
  6671. if prepend.ndim == 0:
  6672. shape = list(a.shape)
  6673. shape[axis] = 1
  6674. prepend = np.broadcast_to(prepend, tuple(shape))
  6675. combined.append(prepend)
  6676. combined.append(a)
  6677. if append is not np._NoValue:
  6678. append = np.ma.asanyarray(append)
  6679. if append.ndim == 0:
  6680. shape = list(a.shape)
  6681. shape[axis] = 1
  6682. append = np.broadcast_to(append, tuple(shape))
  6683. combined.append(append)
  6684. if len(combined) > 1:
  6685. a = np.ma.concatenate(combined, axis)
  6686. # GH 22465 np.diff without prepend/append preserves the mask
  6687. return np.diff(a, n, axis)
  6688. ##############################################################################
  6689. # Extra functions #
  6690. ##############################################################################
  6691. def where(condition, x=_NoValue, y=_NoValue):
  6692. """
  6693. Return a masked array with elements from `x` or `y`, depending on condition.
  6694. .. note::
  6695. When only `condition` is provided, this function is identical to
  6696. `nonzero`. The rest of this documentation covers only the case where
  6697. all three arguments are provided.
  6698. Parameters
  6699. ----------
  6700. condition : array_like, bool
  6701. Where True, yield `x`, otherwise yield `y`.
  6702. x, y : array_like, optional
  6703. Values from which to choose. `x`, `y` and `condition` need to be
  6704. broadcastable to some shape.
  6705. Returns
  6706. -------
  6707. out : MaskedArray
  6708. An masked array with `masked` elements where the condition is masked,
  6709. elements from `x` where `condition` is True, and elements from `y`
  6710. elsewhere.
  6711. See Also
  6712. --------
  6713. numpy.where : Equivalent function in the top-level NumPy module.
  6714. nonzero : The function that is called when x and y are omitted
  6715. Examples
  6716. --------
  6717. >>> import numpy as np
  6718. >>> x = np.ma.array(np.arange(9.).reshape(3, 3), mask=[[0, 1, 0],
  6719. ... [1, 0, 1],
  6720. ... [0, 1, 0]])
  6721. >>> x
  6722. masked_array(
  6723. data=[[0.0, --, 2.0],
  6724. [--, 4.0, --],
  6725. [6.0, --, 8.0]],
  6726. mask=[[False, True, False],
  6727. [ True, False, True],
  6728. [False, True, False]],
  6729. fill_value=1e+20)
  6730. >>> np.ma.where(x > 5, x, -3.1416)
  6731. masked_array(
  6732. data=[[-3.1416, --, -3.1416],
  6733. [--, -3.1416, --],
  6734. [6.0, --, 8.0]],
  6735. mask=[[False, True, False],
  6736. [ True, False, True],
  6737. [False, True, False]],
  6738. fill_value=1e+20)
  6739. """
  6740. # handle the single-argument case
  6741. missing = (x is _NoValue, y is _NoValue).count(True)
  6742. if missing == 1:
  6743. raise ValueError("Must provide both 'x' and 'y' or neither.")
  6744. if missing == 2:
  6745. return nonzero(condition)
  6746. # we only care if the condition is true - false or masked pick y
  6747. cf = filled(condition, False)
  6748. xd = getdata(x)
  6749. yd = getdata(y)
  6750. # we need the full arrays here for correct final dimensions
  6751. cm = getmaskarray(condition)
  6752. xm = getmaskarray(x)
  6753. ym = getmaskarray(y)
  6754. # deal with the fact that masked.dtype == float64, but we don't actually
  6755. # want to treat it as that.
  6756. if x is masked and y is not masked:
  6757. xd = np.zeros((), dtype=yd.dtype)
  6758. xm = np.ones((), dtype=ym.dtype)
  6759. elif y is masked and x is not masked:
  6760. yd = np.zeros((), dtype=xd.dtype)
  6761. ym = np.ones((), dtype=xm.dtype)
  6762. data = np.where(cf, xd, yd)
  6763. mask = np.where(cf, xm, ym)
  6764. mask = np.where(cm, np.ones((), dtype=mask.dtype), mask)
  6765. # collapse the mask, for backwards compatibility
  6766. mask = _shrink_mask(mask)
  6767. return masked_array(data, mask=mask)
  6768. def choose(indices, choices, out=None, mode='raise'):
  6769. """
  6770. Use an index array to construct a new array from a list of choices.
  6771. Given an array of integers and a list of n choice arrays, this method
  6772. will create a new array that merges each of the choice arrays. Where a
  6773. value in `index` is i, the new array will have the value that choices[i]
  6774. contains in the same place.
  6775. Parameters
  6776. ----------
  6777. indices : ndarray of ints
  6778. This array must contain integers in ``[0, n-1]``, where n is the
  6779. number of choices.
  6780. choices : sequence of arrays
  6781. Choice arrays. The index array and all of the choices should be
  6782. broadcastable to the same shape.
  6783. out : array, optional
  6784. If provided, the result will be inserted into this array. It should
  6785. be of the appropriate shape and `dtype`.
  6786. mode : {'raise', 'wrap', 'clip'}, optional
  6787. Specifies how out-of-bounds indices will behave.
  6788. * 'raise' : raise an error
  6789. * 'wrap' : wrap around
  6790. * 'clip' : clip to the range
  6791. Returns
  6792. -------
  6793. merged_array : array
  6794. See Also
  6795. --------
  6796. choose : equivalent function
  6797. Examples
  6798. --------
  6799. >>> import numpy as np
  6800. >>> choice = np.array([[1,1,1], [2,2,2], [3,3,3]])
  6801. >>> a = np.array([2, 1, 0])
  6802. >>> np.ma.choose(a, choice)
  6803. masked_array(data=[3, 2, 1],
  6804. mask=False,
  6805. fill_value=999999)
  6806. """
  6807. def fmask(x):
  6808. "Returns the filled array, or True if masked."
  6809. if x is masked:
  6810. return True
  6811. return filled(x)
  6812. def nmask(x):
  6813. "Returns the mask, True if ``masked``, False if ``nomask``."
  6814. if x is masked:
  6815. return True
  6816. return getmask(x)
  6817. # Get the indices.
  6818. c = filled(indices, 0)
  6819. # Get the masks.
  6820. masks = [nmask(x) for x in choices]
  6821. data = [fmask(x) for x in choices]
  6822. # Construct the mask
  6823. outputmask = np.choose(c, masks, mode=mode)
  6824. outputmask = make_mask(mask_or(outputmask, getmask(indices)),
  6825. copy=False, shrink=True)
  6826. # Get the choices.
  6827. d = np.choose(c, data, mode=mode, out=out).view(MaskedArray)
  6828. if out is not None:
  6829. if isinstance(out, MaskedArray):
  6830. out.__setmask__(outputmask)
  6831. return out
  6832. d.__setmask__(outputmask)
  6833. return d
  6834. def round_(a, decimals=0, out=None):
  6835. """
  6836. Return a copy of a, rounded to 'decimals' places.
  6837. When 'decimals' is negative, it specifies the number of positions
  6838. to the left of the decimal point. The real and imaginary parts of
  6839. complex numbers are rounded separately. Nothing is done if the
  6840. array is not of float type and 'decimals' is greater than or equal
  6841. to 0.
  6842. Parameters
  6843. ----------
  6844. decimals : int
  6845. Number of decimals to round to. May be negative.
  6846. out : array_like
  6847. Existing array to use for output.
  6848. If not given, returns a default copy of a.
  6849. Notes
  6850. -----
  6851. If out is given and does not have a mask attribute, the mask of a
  6852. is lost!
  6853. Examples
  6854. --------
  6855. >>> import numpy as np
  6856. >>> import numpy.ma as ma
  6857. >>> x = [11.2, -3.973, 0.801, -1.41]
  6858. >>> mask = [0, 0, 0, 1]
  6859. >>> masked_x = ma.masked_array(x, mask)
  6860. >>> masked_x
  6861. masked_array(data=[11.2, -3.973, 0.801, --],
  6862. mask=[False, False, False, True],
  6863. fill_value=1e+20)
  6864. >>> ma.round_(masked_x)
  6865. masked_array(data=[11.0, -4.0, 1.0, --],
  6866. mask=[False, False, False, True],
  6867. fill_value=1e+20)
  6868. >>> ma.round(masked_x, decimals=1)
  6869. masked_array(data=[11.2, -4.0, 0.8, --],
  6870. mask=[False, False, False, True],
  6871. fill_value=1e+20)
  6872. >>> ma.round_(masked_x, decimals=-1)
  6873. masked_array(data=[10.0, -0.0, 0.0, --],
  6874. mask=[False, False, False, True],
  6875. fill_value=1e+20)
  6876. """
  6877. if out is None:
  6878. return np.round(a, decimals, out)
  6879. else:
  6880. np.round(getdata(a), decimals, out)
  6881. if hasattr(out, '_mask'):
  6882. out._mask = getmask(a)
  6883. return out
  6884. round = round_
  6885. def _mask_propagate(a, axis):
  6886. """
  6887. Mask whole 1-d vectors of an array that contain masked values.
  6888. """
  6889. a = array(a, subok=False)
  6890. m = getmask(a)
  6891. if m is nomask or not m.any() or axis is None:
  6892. return a
  6893. a._mask = a._mask.copy()
  6894. axes = normalize_axis_tuple(axis, a.ndim)
  6895. for ax in axes:
  6896. a._mask |= m.any(axis=ax, keepdims=True)
  6897. return a
  6898. # Include masked dot here to avoid import problems in getting it from
  6899. # extras.py. Note that it is not included in __all__, but rather exported
  6900. # from extras in order to avoid backward compatibility problems.
  6901. def dot(a, b, strict=False, out=None):
  6902. """
  6903. Return the dot product of two arrays.
  6904. This function is the equivalent of `numpy.dot` that takes masked values
  6905. into account. Note that `strict` and `out` are in different position
  6906. than in the method version. In order to maintain compatibility with the
  6907. corresponding method, it is recommended that the optional arguments be
  6908. treated as keyword only. At some point that may be mandatory.
  6909. Parameters
  6910. ----------
  6911. a, b : masked_array_like
  6912. Inputs arrays.
  6913. strict : bool, optional
  6914. Whether masked data are propagated (True) or set to 0 (False) for
  6915. the computation. Default is False. Propagating the mask means that
  6916. if a masked value appears in a row or column, the whole row or
  6917. column is considered masked.
  6918. out : masked_array, optional
  6919. Output argument. This must have the exact kind that would be returned
  6920. if it was not used. In particular, it must have the right type, must be
  6921. C-contiguous, and its dtype must be the dtype that would be returned
  6922. for `dot(a,b)`. This is a performance feature. Therefore, if these
  6923. conditions are not met, an exception is raised, instead of attempting
  6924. to be flexible.
  6925. See Also
  6926. --------
  6927. numpy.dot : Equivalent function for ndarrays.
  6928. Examples
  6929. --------
  6930. >>> import numpy as np
  6931. >>> a = np.ma.array([[1, 2, 3], [4, 5, 6]], mask=[[1, 0, 0], [0, 0, 0]])
  6932. >>> b = np.ma.array([[1, 2], [3, 4], [5, 6]], mask=[[1, 0], [0, 0], [0, 0]])
  6933. >>> np.ma.dot(a, b)
  6934. masked_array(
  6935. data=[[21, 26],
  6936. [45, 64]],
  6937. mask=[[False, False],
  6938. [False, False]],
  6939. fill_value=999999)
  6940. >>> np.ma.dot(a, b, strict=True)
  6941. masked_array(
  6942. data=[[--, --],
  6943. [--, 64]],
  6944. mask=[[ True, True],
  6945. [ True, False]],
  6946. fill_value=999999)
  6947. """
  6948. if strict is True:
  6949. if np.ndim(a) == 0 or np.ndim(b) == 0:
  6950. pass
  6951. elif b.ndim == 1:
  6952. a = _mask_propagate(a, a.ndim - 1)
  6953. b = _mask_propagate(b, b.ndim - 1)
  6954. else:
  6955. a = _mask_propagate(a, a.ndim - 1)
  6956. b = _mask_propagate(b, b.ndim - 2)
  6957. am = ~getmaskarray(a)
  6958. bm = ~getmaskarray(b)
  6959. if out is None:
  6960. d = np.dot(filled(a, 0), filled(b, 0))
  6961. m = ~np.dot(am, bm)
  6962. if np.ndim(d) == 0:
  6963. d = np.asarray(d)
  6964. r = d.view(get_masked_subclass(a, b))
  6965. r.__setmask__(m)
  6966. return r
  6967. else:
  6968. d = np.dot(filled(a, 0), filled(b, 0), out._data)
  6969. if out.mask.shape != d.shape:
  6970. out._mask = np.empty(d.shape, MaskType)
  6971. np.dot(am, bm, out._mask)
  6972. np.logical_not(out._mask, out._mask)
  6973. return out
  6974. def inner(a, b):
  6975. """
  6976. Returns the inner product of a and b for arrays of floating point types.
  6977. Like the generic NumPy equivalent the product sum is over the last dimension
  6978. of a and b. The first argument is not conjugated.
  6979. """
  6980. fa = filled(a, 0)
  6981. fb = filled(b, 0)
  6982. if fa.ndim == 0:
  6983. fa.shape = (1,)
  6984. if fb.ndim == 0:
  6985. fb.shape = (1,)
  6986. return np.inner(fa, fb).view(MaskedArray)
  6987. inner.__doc__ = doc_note(np.inner.__doc__,
  6988. "Masked values are replaced by 0.")
  6989. innerproduct = inner
  6990. def outer(a, b):
  6991. "maskedarray version of the numpy function."
  6992. fa = filled(a, 0).ravel()
  6993. fb = filled(b, 0).ravel()
  6994. d = np.outer(fa, fb)
  6995. ma = getmask(a)
  6996. mb = getmask(b)
  6997. if ma is nomask and mb is nomask:
  6998. return masked_array(d)
  6999. ma = getmaskarray(a)
  7000. mb = getmaskarray(b)
  7001. m = make_mask(1 - np.outer(1 - ma, 1 - mb), copy=False)
  7002. return masked_array(d, mask=m)
  7003. outer.__doc__ = doc_note(np.outer.__doc__,
  7004. "Masked values are replaced by 0.")
  7005. outerproduct = outer
  7006. def _convolve_or_correlate(f, a, v, mode, propagate_mask):
  7007. """
  7008. Helper function for ma.correlate and ma.convolve
  7009. """
  7010. if propagate_mask:
  7011. # results which are contributed to by either item in any pair being invalid
  7012. mask = (
  7013. f(getmaskarray(a), np.ones(np.shape(v), dtype=bool), mode=mode)
  7014. | f(np.ones(np.shape(a), dtype=bool), getmaskarray(v), mode=mode)
  7015. )
  7016. data = f(getdata(a), getdata(v), mode=mode)
  7017. else:
  7018. # results which are not contributed to by any pair of valid elements
  7019. mask = ~f(~getmaskarray(a), ~getmaskarray(v), mode=mode)
  7020. data = f(filled(a, 0), filled(v, 0), mode=mode)
  7021. return masked_array(data, mask=mask)
  7022. def correlate(a, v, mode='valid', propagate_mask=True):
  7023. """
  7024. Cross-correlation of two 1-dimensional sequences.
  7025. Parameters
  7026. ----------
  7027. a, v : array_like
  7028. Input sequences.
  7029. mode : {'valid', 'same', 'full'}, optional
  7030. Refer to the `np.convolve` docstring. Note that the default
  7031. is 'valid', unlike `convolve`, which uses 'full'.
  7032. propagate_mask : bool
  7033. If True, then a result element is masked if any masked element contributes towards it.
  7034. If False, then a result element is only masked if no non-masked element
  7035. contribute towards it
  7036. Returns
  7037. -------
  7038. out : MaskedArray
  7039. Discrete cross-correlation of `a` and `v`.
  7040. See Also
  7041. --------
  7042. numpy.correlate : Equivalent function in the top-level NumPy module.
  7043. Examples
  7044. --------
  7045. Basic correlation:
  7046. >>> a = np.ma.array([1, 2, 3])
  7047. >>> v = np.ma.array([0, 1, 0])
  7048. >>> np.ma.correlate(a, v, mode='valid')
  7049. masked_array(data=[2],
  7050. mask=[False],
  7051. fill_value=999999)
  7052. Correlation with masked elements:
  7053. >>> a = np.ma.array([1, 2, 3], mask=[False, True, False])
  7054. >>> v = np.ma.array([0, 1, 0])
  7055. >>> np.ma.correlate(a, v, mode='valid', propagate_mask=True)
  7056. masked_array(data=[--],
  7057. mask=[ True],
  7058. fill_value=999999,
  7059. dtype=int64)
  7060. Correlation with different modes and mixed array types:
  7061. >>> a = np.ma.array([1, 2, 3])
  7062. >>> v = np.ma.array([0, 1, 0])
  7063. >>> np.ma.correlate(a, v, mode='full')
  7064. masked_array(data=[0, 1, 2, 3, 0],
  7065. mask=[False, False, False, False, False],
  7066. fill_value=999999)
  7067. """
  7068. return _convolve_or_correlate(np.correlate, a, v, mode, propagate_mask)
  7069. def convolve(a, v, mode='full', propagate_mask=True):
  7070. """
  7071. Returns the discrete, linear convolution of two one-dimensional sequences.
  7072. Parameters
  7073. ----------
  7074. a, v : array_like
  7075. Input sequences.
  7076. mode : {'valid', 'same', 'full'}, optional
  7077. Refer to the `np.convolve` docstring.
  7078. propagate_mask : bool
  7079. If True, then if any masked element is included in the sum for a result
  7080. element, then the result is masked.
  7081. If False, then the result element is only masked if no non-masked cells
  7082. contribute towards it
  7083. Returns
  7084. -------
  7085. out : MaskedArray
  7086. Discrete, linear convolution of `a` and `v`.
  7087. See Also
  7088. --------
  7089. numpy.convolve : Equivalent function in the top-level NumPy module.
  7090. """
  7091. return _convolve_or_correlate(np.convolve, a, v, mode, propagate_mask)
  7092. def allequal(a, b, fill_value=True):
  7093. """
  7094. Return True if all entries of a and b are equal, using
  7095. fill_value as a truth value where either or both are masked.
  7096. Parameters
  7097. ----------
  7098. a, b : array_like
  7099. Input arrays to compare.
  7100. fill_value : bool, optional
  7101. Whether masked values in a or b are considered equal (True) or not
  7102. (False).
  7103. Returns
  7104. -------
  7105. y : bool
  7106. Returns True if the two arrays are equal within the given
  7107. tolerance, False otherwise. If either array contains NaN,
  7108. then False is returned.
  7109. See Also
  7110. --------
  7111. all, any
  7112. numpy.ma.allclose
  7113. Examples
  7114. --------
  7115. >>> import numpy as np
  7116. >>> a = np.ma.array([1e10, 1e-7, 42.0], mask=[0, 0, 1])
  7117. >>> a
  7118. masked_array(data=[10000000000.0, 1e-07, --],
  7119. mask=[False, False, True],
  7120. fill_value=1e+20)
  7121. >>> b = np.array([1e10, 1e-7, -42.0])
  7122. >>> b
  7123. array([ 1.00000000e+10, 1.00000000e-07, -4.20000000e+01])
  7124. >>> np.ma.allequal(a, b, fill_value=False)
  7125. False
  7126. >>> np.ma.allequal(a, b)
  7127. True
  7128. """
  7129. m = mask_or(getmask(a), getmask(b))
  7130. if m is nomask:
  7131. x = getdata(a)
  7132. y = getdata(b)
  7133. d = umath.equal(x, y)
  7134. return d.all()
  7135. elif fill_value:
  7136. x = getdata(a)
  7137. y = getdata(b)
  7138. d = umath.equal(x, y)
  7139. dm = array(d, mask=m, copy=False)
  7140. return dm.filled(True).all(None)
  7141. else:
  7142. return False
  7143. def allclose(a, b, masked_equal=True, rtol=1e-5, atol=1e-8):
  7144. """
  7145. Returns True if two arrays are element-wise equal within a tolerance.
  7146. This function is equivalent to `allclose` except that masked values
  7147. are treated as equal (default) or unequal, depending on the `masked_equal`
  7148. argument.
  7149. Parameters
  7150. ----------
  7151. a, b : array_like
  7152. Input arrays to compare.
  7153. masked_equal : bool, optional
  7154. Whether masked values in `a` and `b` are considered equal (True) or not
  7155. (False). They are considered equal by default.
  7156. rtol : float, optional
  7157. Relative tolerance. The relative difference is equal to ``rtol * b``.
  7158. Default is 1e-5.
  7159. atol : float, optional
  7160. Absolute tolerance. The absolute difference is equal to `atol`.
  7161. Default is 1e-8.
  7162. Returns
  7163. -------
  7164. y : bool
  7165. Returns True if the two arrays are equal within the given
  7166. tolerance, False otherwise. If either array contains NaN, then
  7167. False is returned.
  7168. See Also
  7169. --------
  7170. all, any
  7171. numpy.allclose : the non-masked `allclose`.
  7172. Notes
  7173. -----
  7174. If the following equation is element-wise True, then `allclose` returns
  7175. True::
  7176. absolute(`a` - `b`) <= (`atol` + `rtol` * absolute(`b`))
  7177. Return True if all elements of `a` and `b` are equal subject to
  7178. given tolerances.
  7179. Examples
  7180. --------
  7181. >>> import numpy as np
  7182. >>> a = np.ma.array([1e10, 1e-7, 42.0], mask=[0, 0, 1])
  7183. >>> a
  7184. masked_array(data=[10000000000.0, 1e-07, --],
  7185. mask=[False, False, True],
  7186. fill_value=1e+20)
  7187. >>> b = np.ma.array([1e10, 1e-8, -42.0], mask=[0, 0, 1])
  7188. >>> np.ma.allclose(a, b)
  7189. False
  7190. >>> a = np.ma.array([1e10, 1e-8, 42.0], mask=[0, 0, 1])
  7191. >>> b = np.ma.array([1.00001e10, 1e-9, -42.0], mask=[0, 0, 1])
  7192. >>> np.ma.allclose(a, b)
  7193. True
  7194. >>> np.ma.allclose(a, b, masked_equal=False)
  7195. False
  7196. Masked values are not compared directly.
  7197. >>> a = np.ma.array([1e10, 1e-8, 42.0], mask=[0, 0, 1])
  7198. >>> b = np.ma.array([1.00001e10, 1e-9, 42.0], mask=[0, 0, 1])
  7199. >>> np.ma.allclose(a, b)
  7200. True
  7201. >>> np.ma.allclose(a, b, masked_equal=False)
  7202. False
  7203. """
  7204. x = masked_array(a, copy=False)
  7205. y = masked_array(b, copy=False)
  7206. # make sure y is an inexact type to avoid abs(MIN_INT); will cause
  7207. # casting of x later.
  7208. # NOTE: We explicitly allow timedelta, which used to work. This could
  7209. # possibly be deprecated. See also gh-18286.
  7210. # timedelta works if `atol` is an integer or also a timedelta.
  7211. # Although, the default tolerances are unlikely to be useful
  7212. if y.dtype.kind != "m":
  7213. dtype = np.result_type(y, 1.)
  7214. if y.dtype != dtype:
  7215. y = masked_array(y, dtype=dtype, copy=False)
  7216. m = mask_or(getmask(x), getmask(y))
  7217. xinf = np.isinf(masked_array(x, copy=False, mask=m)).filled(False)
  7218. # If we have some infs, they should fall at the same place.
  7219. if not np.all(xinf == filled(np.isinf(y), False)):
  7220. return False
  7221. # No infs at all
  7222. if not np.any(xinf):
  7223. d = filled(less_equal(absolute(x - y), atol + rtol * absolute(y)),
  7224. masked_equal)
  7225. return np.all(d)
  7226. if not np.all(filled(x[xinf] == y[xinf], masked_equal)):
  7227. return False
  7228. x = x[~xinf]
  7229. y = y[~xinf]
  7230. d = filled(less_equal(absolute(x - y), atol + rtol * absolute(y)),
  7231. masked_equal)
  7232. return np.all(d)
  7233. def asarray(a, dtype=None, order=None):
  7234. """
  7235. Convert the input to a masked array of the given data-type.
  7236. No copy is performed if the input is already an `ndarray`. If `a` is
  7237. a subclass of `MaskedArray`, a base class `MaskedArray` is returned.
  7238. Parameters
  7239. ----------
  7240. a : array_like
  7241. Input data, in any form that can be converted to a masked array. This
  7242. includes lists, lists of tuples, tuples, tuples of tuples, tuples
  7243. of lists, ndarrays and masked arrays.
  7244. dtype : dtype, optional
  7245. By default, the data-type is inferred from the input data.
  7246. order : {'C', 'F'}, optional
  7247. Whether to use row-major ('C') or column-major ('FORTRAN') memory
  7248. representation. Default is 'C'.
  7249. Returns
  7250. -------
  7251. out : MaskedArray
  7252. Masked array interpretation of `a`.
  7253. See Also
  7254. --------
  7255. asanyarray : Similar to `asarray`, but conserves subclasses.
  7256. Examples
  7257. --------
  7258. >>> import numpy as np
  7259. >>> x = np.arange(10.).reshape(2, 5)
  7260. >>> x
  7261. array([[0., 1., 2., 3., 4.],
  7262. [5., 6., 7., 8., 9.]])
  7263. >>> np.ma.asarray(x)
  7264. masked_array(
  7265. data=[[0., 1., 2., 3., 4.],
  7266. [5., 6., 7., 8., 9.]],
  7267. mask=False,
  7268. fill_value=1e+20)
  7269. >>> type(np.ma.asarray(x))
  7270. <class 'numpy.ma.MaskedArray'>
  7271. """
  7272. order = order or 'C'
  7273. return masked_array(a, dtype=dtype, copy=False, keep_mask=True,
  7274. subok=False, order=order)
  7275. def asanyarray(a, dtype=None):
  7276. """
  7277. Convert the input to a masked array, conserving subclasses.
  7278. If `a` is a subclass of `MaskedArray`, its class is conserved.
  7279. No copy is performed if the input is already an `ndarray`.
  7280. Parameters
  7281. ----------
  7282. a : array_like
  7283. Input data, in any form that can be converted to an array.
  7284. dtype : dtype, optional
  7285. By default, the data-type is inferred from the input data.
  7286. order : {'C', 'F'}, optional
  7287. Whether to use row-major ('C') or column-major ('FORTRAN') memory
  7288. representation. Default is 'C'.
  7289. Returns
  7290. -------
  7291. out : MaskedArray
  7292. MaskedArray interpretation of `a`.
  7293. See Also
  7294. --------
  7295. asarray : Similar to `asanyarray`, but does not conserve subclass.
  7296. Examples
  7297. --------
  7298. >>> import numpy as np
  7299. >>> x = np.arange(10.).reshape(2, 5)
  7300. >>> x
  7301. array([[0., 1., 2., 3., 4.],
  7302. [5., 6., 7., 8., 9.]])
  7303. >>> np.ma.asanyarray(x)
  7304. masked_array(
  7305. data=[[0., 1., 2., 3., 4.],
  7306. [5., 6., 7., 8., 9.]],
  7307. mask=False,
  7308. fill_value=1e+20)
  7309. >>> type(np.ma.asanyarray(x))
  7310. <class 'numpy.ma.MaskedArray'>
  7311. """
  7312. # workaround for #8666, to preserve identity. Ideally the bottom line
  7313. # would handle this for us.
  7314. if isinstance(a, MaskedArray) and (dtype is None or dtype == a.dtype):
  7315. return a
  7316. return masked_array(a, dtype=dtype, copy=False, keep_mask=True, subok=True)
  7317. ##############################################################################
  7318. # Pickling #
  7319. ##############################################################################
  7320. def fromfile(file, dtype=float, count=-1, sep=''):
  7321. raise NotImplementedError(
  7322. "fromfile() not yet implemented for a MaskedArray.")
  7323. def fromflex(fxarray):
  7324. """
  7325. Build a masked array from a suitable flexible-type array.
  7326. The input array has to have a data-type with ``_data`` and ``_mask``
  7327. fields. This type of array is output by `MaskedArray.toflex`.
  7328. Parameters
  7329. ----------
  7330. fxarray : ndarray
  7331. The structured input array, containing ``_data`` and ``_mask``
  7332. fields. If present, other fields are discarded.
  7333. Returns
  7334. -------
  7335. result : MaskedArray
  7336. The constructed masked array.
  7337. See Also
  7338. --------
  7339. MaskedArray.toflex : Build a flexible-type array from a masked array.
  7340. Examples
  7341. --------
  7342. >>> import numpy as np
  7343. >>> x = np.ma.array(np.arange(9).reshape(3, 3), mask=[0] + [1, 0] * 4)
  7344. >>> rec = x.toflex()
  7345. >>> rec
  7346. array([[(0, False), (1, True), (2, False)],
  7347. [(3, True), (4, False), (5, True)],
  7348. [(6, False), (7, True), (8, False)]],
  7349. dtype=[('_data', '<i8'), ('_mask', '?')])
  7350. >>> x2 = np.ma.fromflex(rec)
  7351. >>> x2
  7352. masked_array(
  7353. data=[[0, --, 2],
  7354. [--, 4, --],
  7355. [6, --, 8]],
  7356. mask=[[False, True, False],
  7357. [ True, False, True],
  7358. [False, True, False]],
  7359. fill_value=999999)
  7360. Extra fields can be present in the structured array but are discarded:
  7361. >>> dt = [('_data', '<i4'), ('_mask', '|b1'), ('field3', '<f4')]
  7362. >>> rec2 = np.zeros((2, 2), dtype=dt)
  7363. >>> rec2
  7364. array([[(0, False, 0.), (0, False, 0.)],
  7365. [(0, False, 0.), (0, False, 0.)]],
  7366. dtype=[('_data', '<i4'), ('_mask', '?'), ('field3', '<f4')])
  7367. >>> y = np.ma.fromflex(rec2)
  7368. >>> y
  7369. masked_array(
  7370. data=[[0, 0],
  7371. [0, 0]],
  7372. mask=[[False, False],
  7373. [False, False]],
  7374. fill_value=np.int64(999999),
  7375. dtype=int32)
  7376. """
  7377. return masked_array(fxarray['_data'], mask=fxarray['_mask'])
  7378. class _convert2ma:
  7379. """
  7380. Convert functions from numpy to numpy.ma.
  7381. Parameters
  7382. ----------
  7383. _methodname : string
  7384. Name of the method to transform.
  7385. """
  7386. __doc__ = None
  7387. def __init__(self, funcname, np_ret, np_ma_ret, params=None):
  7388. self._func = getattr(np, funcname)
  7389. self.__doc__ = self.getdoc(np_ret, np_ma_ret)
  7390. self._extras = params or {}
  7391. def getdoc(self, np_ret, np_ma_ret):
  7392. "Return the doc of the function (from the doc of the method)."
  7393. doc = getattr(self._func, '__doc__', None)
  7394. sig = get_object_signature(self._func)
  7395. if doc:
  7396. doc = self._replace_return_type(doc, np_ret, np_ma_ret)
  7397. # Add the signature of the function at the beginning of the doc
  7398. if sig:
  7399. sig = "%s%s\n" % (self._func.__name__, sig)
  7400. doc = sig + doc
  7401. return doc
  7402. def _replace_return_type(self, doc, np_ret, np_ma_ret):
  7403. """
  7404. Replace documentation of ``np`` function's return type.
  7405. Replaces it with the proper type for the ``np.ma`` function.
  7406. Parameters
  7407. ----------
  7408. doc : str
  7409. The documentation of the ``np`` method.
  7410. np_ret : str
  7411. The return type string of the ``np`` method that we want to
  7412. replace. (e.g. "out : ndarray")
  7413. np_ma_ret : str
  7414. The return type string of the ``np.ma`` method.
  7415. (e.g. "out : MaskedArray")
  7416. """
  7417. if np_ret not in doc:
  7418. raise RuntimeError(
  7419. f"Failed to replace `{np_ret}` with `{np_ma_ret}`. "
  7420. f"The documentation string for return type, {np_ret}, is not "
  7421. f"found in the docstring for `np.{self._func.__name__}`. "
  7422. f"Fix the docstring for `np.{self._func.__name__}` or "
  7423. "update the expected string for return type."
  7424. )
  7425. return doc.replace(np_ret, np_ma_ret)
  7426. def __call__(self, *args, **params):
  7427. # Find the common parameters to the call and the definition
  7428. _extras = self._extras
  7429. common_params = set(params).intersection(_extras)
  7430. # Drop the common parameters from the call
  7431. for p in common_params:
  7432. _extras[p] = params.pop(p)
  7433. # Get the result
  7434. result = self._func.__call__(*args, **params).view(MaskedArray)
  7435. if "fill_value" in common_params:
  7436. result.fill_value = _extras.get("fill_value", None)
  7437. if "hardmask" in common_params:
  7438. result._hardmask = bool(_extras.get("hard_mask", False))
  7439. return result
  7440. arange = _convert2ma(
  7441. 'arange',
  7442. params=dict(fill_value=None, hardmask=False),
  7443. np_ret='arange : ndarray',
  7444. np_ma_ret='arange : MaskedArray',
  7445. )
  7446. clip = _convert2ma(
  7447. 'clip',
  7448. params=dict(fill_value=None, hardmask=False),
  7449. np_ret='clipped_array : ndarray',
  7450. np_ma_ret='clipped_array : MaskedArray',
  7451. )
  7452. empty = _convert2ma(
  7453. 'empty',
  7454. params=dict(fill_value=None, hardmask=False),
  7455. np_ret='out : ndarray',
  7456. np_ma_ret='out : MaskedArray',
  7457. )
  7458. empty_like = _convert2ma(
  7459. 'empty_like',
  7460. np_ret='out : ndarray',
  7461. np_ma_ret='out : MaskedArray',
  7462. )
  7463. frombuffer = _convert2ma(
  7464. 'frombuffer',
  7465. np_ret='out : ndarray',
  7466. np_ma_ret='out: MaskedArray',
  7467. )
  7468. fromfunction = _convert2ma(
  7469. 'fromfunction',
  7470. np_ret='fromfunction : any',
  7471. np_ma_ret='fromfunction: MaskedArray',
  7472. )
  7473. identity = _convert2ma(
  7474. 'identity',
  7475. params=dict(fill_value=None, hardmask=False),
  7476. np_ret='out : ndarray',
  7477. np_ma_ret='out : MaskedArray',
  7478. )
  7479. indices = _convert2ma(
  7480. 'indices',
  7481. params=dict(fill_value=None, hardmask=False),
  7482. np_ret='grid : one ndarray or tuple of ndarrays',
  7483. np_ma_ret='grid : one MaskedArray or tuple of MaskedArrays',
  7484. )
  7485. ones = _convert2ma(
  7486. 'ones',
  7487. params=dict(fill_value=None, hardmask=False),
  7488. np_ret='out : ndarray',
  7489. np_ma_ret='out : MaskedArray',
  7490. )
  7491. ones_like = _convert2ma(
  7492. 'ones_like',
  7493. np_ret='out : ndarray',
  7494. np_ma_ret='out : MaskedArray',
  7495. )
  7496. squeeze = _convert2ma(
  7497. 'squeeze',
  7498. params=dict(fill_value=None, hardmask=False),
  7499. np_ret='squeezed : ndarray',
  7500. np_ma_ret='squeezed : MaskedArray',
  7501. )
  7502. zeros = _convert2ma(
  7503. 'zeros',
  7504. params=dict(fill_value=None, hardmask=False),
  7505. np_ret='out : ndarray',
  7506. np_ma_ret='out : MaskedArray',
  7507. )
  7508. zeros_like = _convert2ma(
  7509. 'zeros_like',
  7510. np_ret='out : ndarray',
  7511. np_ma_ret='out : MaskedArray',
  7512. )
  7513. def append(a, b, axis=None):
  7514. """Append values to the end of an array.
  7515. Parameters
  7516. ----------
  7517. a : array_like
  7518. Values are appended to a copy of this array.
  7519. b : array_like
  7520. These values are appended to a copy of `a`. It must be of the
  7521. correct shape (the same shape as `a`, excluding `axis`). If `axis`
  7522. is not specified, `b` can be any shape and will be flattened
  7523. before use.
  7524. axis : int, optional
  7525. The axis along which `v` are appended. If `axis` is not given,
  7526. both `a` and `b` are flattened before use.
  7527. Returns
  7528. -------
  7529. append : MaskedArray
  7530. A copy of `a` with `b` appended to `axis`. Note that `append`
  7531. does not occur in-place: a new array is allocated and filled. If
  7532. `axis` is None, the result is a flattened array.
  7533. See Also
  7534. --------
  7535. numpy.append : Equivalent function in the top-level NumPy module.
  7536. Examples
  7537. --------
  7538. >>> import numpy as np
  7539. >>> import numpy.ma as ma
  7540. >>> a = ma.masked_values([1, 2, 3], 2)
  7541. >>> b = ma.masked_values([[4, 5, 6], [7, 8, 9]], 7)
  7542. >>> ma.append(a, b)
  7543. masked_array(data=[1, --, 3, 4, 5, 6, --, 8, 9],
  7544. mask=[False, True, False, False, False, False, True, False,
  7545. False],
  7546. fill_value=999999)
  7547. """
  7548. return concatenate([a, b], axis)