Package: apteco
RequirementsPython 3.6+Access to an installation of the Apteco APIThe Apteco API (which also goes under the nameOrbit API)
is part of the Apteco Orbit™ installation.
If you have access to Apteco Orbit™, you also have access to the Apteco API!
If you’re not sure about this, contact whoever administers your Apteco software,
or get in touch with Apteco support (support@apteco.com).InstallationYou can install the package the usual way from PyPI usingpip:python -m pip install aptecoLogging inYour login credentials are the same username and password
you would use to log in to Apteco Orbit™:>>>fromaptecoimportlogin>>>my_session=login("https://my-site.com/OrbitAPI","my_data_view","my_system","jdoe")You will be asked to enter your password in the terminal, which won’t be echoed.
If Python is unable to ask for your password in this way,
it will provide a pop-up box instead.
This might appear in the background,
so check your taskbar for a new window if nothing seems to be happening.If you don’t want to enter your password every time,
there’s also alogin_with_passwordfunction which takes your password
as a fifth argument:>>>fromaptecoimportlogin_with_password>>>my_session=login_with_password(..."https://my-site.com/OrbitAPI",..."my_data_view",..."my_system",..."jdoe",..."password",# password is in plain sight in the code!...)TablesTables are accessed through thetablesattribute on theSessionobject.
You can retrieve a table using its name:>>>bookings=my_session.tables["Bookings"]Tableobjects have properties for various metadata:>>>print(...f"There are{bookings.total_records:,}"...f"{bookings.plural.lower()}"...f" in the system."...)Thereare2,130,081bookingsinthesystem.VariablesVariables are accessed through thevariablesattribute
on theSessionobject.
You can retrieve a variable using its name or description:>>>occupation=my_session.variables["peOccu"]# name>>>cost=my_session.variables["Cost"]# descriptionEach table also has avariablesattribute
for accessing the variables on that table:>>>occupation=people.variables["peOccu"]>>>cost=bookings.variables["Cost"]For convenience you can access variables by indexing into theTableitself:>>>occupation=people["peOccu"]>>>cost=bookings["Cost"]Variableobjects have attributes with various metadata:>>>occupation.type<VariableType.SELECTOR:'Selector'>>>>cost.description'Cost'Creating selectionsYou can use the Python operators withVariableobjects to build selections
based on criteria and return a count:>>>sweden=bookings["Destination"]=="29">>>sweden.count()25207You can specify multiple values using anyiterable:>>>people=my_session.tables["People"]>>>high_earners=people["Income"]==(f"{i:02}"foriinrange(7,12))>>>high_earners.count()7114You can use other operators as well; for example, to exclude values:>>>households=my_session.tables["Households"]>>>uk_only=households["Region"]!="14"# 14 is Channel Islands>>>uk_only.count()741572Or to allow a range of values:>>>low_profit=bookings["Profit"]<=25>>>low_profit.count()211328>>>second_half_of_alphabet=people["Surname"]>="N">>>second_half_of_alphabet.count()410954Date and DateTime variables use the built-indatetimemodule:>>>fromdatetimeimportdate,datetime>>>bookings_before_2019=bookings["Booking Date"]<=date(2018,12,31)>>>bookings_before_2019.count()972439You can take advantage of functionality available in other Python packages:>>>fromdateutil.relativedeltaimportrelativedelta>>>under_30=people["DOB"]>=date.today()-relativedelta(years=30)>>>under_30.count()207737Combining selectionsYou can use the&|operators to combine selection criteria:>>>sweden=bookings["Destination"]=="29">>>cost_at_least_2k=bookings["Cost"]>=2000>>>expensive_sweden=sweden&cost_at_least_2k>>>expensive_sweden.count()632>>>student=people["Occupation"]=="4">>>under_21=people["DOB"]>=date.today()-relativedelta(years=21)>>>eligible_for_discount=student|under_21>>>eligible_for_discount.count()188364The~operator negates a selection:>>>pay_full_price=~eligible_for_discount>>>pay_full_price.count()968189You can join clauses from different tables and it will automatically handle
the required table changes:>>>high_affordability=high_earners|cost_at_least_2k# will resolve to people>>>high_affordability.count()56096>>>high_affordability.table_name'People'The left-most clause determines the resolve table:>>>female=people["Gender"]=="F">>>usa=bookings["Destination"]=="38">>>female.table_name'People'>>>usa.table_name'Bookings'>>>(female&usa).table_name'People'>>>(usa&female).table_name'Bookings'You can manually set the resolve table using the*operator:>>>bookings_by_under_21s=bookings*under_21>>>bookings_by_under_21s.count()135100>>>bookings_by_under_21s.table_name'Bookings'Compound clauses follow Python operator precedence:>>>student_or_young_female=student|female&under_21>>>student_or_young_female.count()166708>>>student_or_female_must_be_young=(student|female)&under_21>>>student_or_female_must_be_young.count()49225Be especially careful where compound clauses involve table changes:>>>women_to_sweden=female&sweden>>>women_to_sweden.count()# selection on People table8674>>>audience_1=bookings*(female&sweden)>>>audience_1.count()# bookings by women who've been to sweden23553>>>audience_2=(bookings*female)&sweden>>>audience_2.count()# bookings made by a woman, with destination of sweden8687Creating data gridsYou can create a data grid from a table:>>>urn=bookings["Booking URN"]>>>dest=bookings["Destination"]>>>occupation=people["Occupation"]>>>town=households["Town"]>>>datagrid=bookings.datagrid([urn,dest,cost,occupation,town])Convert it to a Pandas DataFrame:>>>datagrid.to_df()BookingURNDestinationCostOccupationTown010001265France1392.35SalesExecutiveAberdeen110001266France780.34SalesExecutiveAberdeen210011532Germany181.68ManualWorkerAlford310011533Germany300.67ManualWorkerAlford410015830Unclassified228.70SalesExecutiveMacduff.................99510996176UnitedStates241.24ProfessionalGlenrothes99610996177Greece343.23ManagerGlenrothes99710996178UnitedStates636.22ManagerGlenrothes99810996179UnitedStates356.21ManagerGlenrothes99910996180UnitedStates438.20ManagerGlenrothes[1000rowsx5columns]You can use a base selection to filter the records:>>>sweden=dest=="29">>>sweden_datagrid=sweden.datagrid([urn,dest,cost,occupation,town])>>>sweden_datagrid.to_df()BookingURNDestinationCostOccupationTown010172319Sweden1201.81SalesExecutiveBolton110384970Sweden344.30ManagerChelmsford210421011Sweden322.89SalesExecutiveCroydon310425298Sweden880.02StudentSouthCroydon410479109Sweden172.91RetailWorkerNantwich.................99511471824Sweden118.76SalesExecutiveKing's Lynn99611576762Sweden652.38PublicSectorRedhill99711576764Sweden183.36PublicSectorRedhill99811682962Sweden1166.38ManagerLondon99911754655Sweden192.45SalesExecutiveAscot[1000rowsx5columns]You can filter using a selection from a different table:>>>manchester=households["Region"]=="13">>>manc_datagrid=manchester.datagrid(...[urn,dest,cost,occupation,town],table=bookings...)>>>manc_datagrid.to_df()BookingURNDestinationCostOccupationTown010172319Sweden1201.81SalesExecutiveBolton110172320UnitedStates1616.80SalesExecutiveBolton210173729France581.71StudentBolton310173730France2224.70StudentBolton410177047France686.53SalesExecutiveBolton.................99511739340Australia316.60ProfessionalStalybridge99611739342Unclassified316.58SalesExecutiveStalybridge99712087034Greece1305.66PublicSectorAltrincham99812087035UnitedStates585.65PublicSectorAltrincham99912087036Australia496.64PublicSectorAltrincham[1000rowsx5columns]Creating cubesYou can create a cube from a table:>>>occupation=people["Occupation"]>>>income=people["Income"]>>>gender=people["Gender"]>>>cube=people.cube([occupation,income,gender])Convert it to a Pandas DataFrame:>>>df=cube.to_df()>>>df.head(10)PeopleOccupationIncomeGenderManualWorker<£10kFemale15624Male5321Unknown5£10-20kFemale43051Male5992Unknown25£20-30kFemale1498Male649Unknown14£30-40kFemale675You can pivot the dimensions to make it easier to read:>>>df.unstack(level=0)People...OccupationDirectorManager...StudentUnemployedIncomeGender...<£10kFemale12794649...2800221385Male8322926...142968386Unknown416...10155£10-20kFemale411616665...3946217230Male21399123...179174532Unknown947...25368£100k+Female21...20Male10...30Unknown10...10£20-30kFemale12676238...66695747Male10505315...52741345Unknown545...22236£30-40kFemale15916621...56903117Male19409713...63451049Unknown46140...63519£40-50kFemale265965...587262Male5181800...943115Unknown2258...29110£50-60kFemale336806...425277Male6071677...69269Unknown4788...6489£60-70kFemale40112...5458Male96220...958Unknown1116...1717£70-80kFemale4496...4227Male102179...635Unknown1222...155£80-90kFemale1111...30Male1413...160Unknown43...50£90-100kFemale10...11Male117...40Unknown36...90[33rowsx10columns]You can use a base selection to filter the records:>>>occupation=people["Occupation"]>>>region=households["Region"]>>>student=occupation=="4">>>student_cube=student.cube([occupation,dest,region])>>>student_df=student_cube.to_df()>>>student_df.head()PeopleOccupationDestinationRegionManualWorkerAustraliaNorth0NorthWest(ExcludingGtrManchester)0SouthEast(OutsideM25)0SouthWest0EastMidlands0Selecting only cells whereOccupationisStudent,
and pivotingDestinationdimension:>>>student_df.loc["Student"].unstack(level=0)People...DestinationAustraliaDenmark...SwedenUnitedStatesRegion...ChannelIslands461...1081EastAnglia9890...109905EastMidlands19560...1741762GreaterManchester11971...1471089North9592...115869NorthWest(ExcludingGtrManchester)15942...1771429NorthernIreland4670...42492Scotland20611...2241964SouthEast(InsideM25)39350...3903580SouthEast(OutsideM25)62551...6085587SouthWest23100...1822037Wales9740...122860WestMidlands26430...2882362YorkshireandHumber22950...2492089[14rowsx19columns]You can use a selection from a different table to filter the records in the cube:>>>manchester=region=="13">>>manc_cube=manchester.cube([occupation,dest,region],table=bookings)>>>manc_cube.to_df()BookingsOccupationDestinationRegionManualWorkerAustraliaNorth0NorthWest(ExcludingGtrManchester)0SouthEast(OutsideM25)0SouthWest0EastMidlands0...RetiredSouthAfricaScotland0Wales0NorthernIreland0GreaterManchester0ChannelIslands0[2660rowsx1columns]You can find the complete documentation
including a more thoroughtutorialon theApteco website.