> ## Documentation Index
> Fetch the complete documentation index at: https://docs.activeviam.com/llms.txt
> Use this file to discover all available pages before exploring further.

# shift()

<span id="atoti.shift" />

> atoti.shift(<br />
>     *measure*: VariableMeasureConvertible,<br />
>     *on*: [Hierarchy](./atoti.Hierarchy#atoti.Hierarchy),<br />
>     /,<br />
>     \*,<br />
>     *offset*: [int](https://docs.python.org/3/library/functions.html#int) = `1`,<br />
>     *partitioning*: [Level](./atoti.Level#atoti.Level) | [None](https://docs.python.org/3/library/constants.html#None) = `None`,<br />
>     *mode*: [Literal](https://docs.python.org/3/library/typing.html#typing.Literal)\['measure', 'hierarchy'] = `'measure'`,<br />
> ) → MeasureDefinition

Return a measure equal to the passed measure shifted to another member of the hierarchy.

### Parameters

<h4 id="atoti.shift.measure">
  *measure*
</h4>

The measure to shift.

<h4 id="atoti.shift.on">
  *on*
</h4>

The hierarchy to shift on.

<h4 id="atoti.shift.offset">
  *offset*
</h4>

The number of members to shift by.

```pycon theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
>>> df = pd.DataFrame(
...     columns=["Country", "City", "Price"],
...     data=[
...         ("France", "Lille", 1),
...         ("France", "Marseille", None),
...         ("France", "Nantes", 3),
...         ("France", "Paris", 4),
...         ("Japan", "Sapporo", 5),
...         ("Japan", "Tokyo", 6),
...         ("Japan", "Yokohama", None),
...     ],
... )
>>> table = session.read_pandas(
...     df, keys={"Country", "City"}, table_name="Country and city"
... )
>>> cube = session.create_cube(table)
>>> h, l, m = cube.hierarchies, cube.levels, cube.measures
>>> m["Shifted by -1"] = tt.shift(m["Price.SUM"], h["City"], offset=-1)
>>> m["Shifted by 2"] = tt.shift(m["Price.SUM"], h["City"], offset=2)
>>> cube.query(
...     m["Price.SUM"],
...     m["Shifted by -1"],
...     m["Shifted by 2"],
...     levels=[l["City"]],
...     include_totals=True,
... )
          Price.SUM Shifted by -1 Shifted by 2
City
Total         19.00
Lille          1.00                       3.00
Marseille                    1.00         4.00
Nantes         3.00                       5.00
Paris          4.00          3.00         6.00
Sapporo        5.00          4.00
Tokyo          6.00          5.00
Yokohama                     6.00
>>> del m["Shifted by -1"]
>>> del m["Shifted by 2"]
```

<h4 id="atoti.shift.partitioning">
  *partitioning*
</h4>

The level in the hierarchy at which to start over again.

```pycon theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
>>> h["Geography"] = [l["Country"], l["City"]]
>>> for name in h["Geography"]:
...     del h[name]
>>> m["No partitioning"] = tt.shift(m["Price.SUM"], h["Geography"])
>>> m["Partitioned by Country"] = tt.shift(
...     m["Price.SUM"],
...     h["Geography"],
...     partitioning=l["Country"],
... )
>>> cube.query(
...     m["Price.SUM"],
...     m["No partitioning"],
...     m["Partitioned by Country"],
...     levels=[l["City"]],
...     include_totals=True,
... )
                  Price.SUM No partitioning Partitioned by Country
Country City
Total                 19.00
France                 8.00           11.00
        Lille          1.00
        Marseille                      3.00                   3.00
        Nantes         3.00            4.00                   4.00
        Paris          4.00            5.00
Japan                 11.00
        Sapporo        5.00            6.00                   6.00
        Tokyo          6.00
```

<h4 id="atoti.shift.mode">
  *mode*
</h4>

Whether the shift is driven by the values of the input *measure* in the query result or by the members of the *on* hierarchy.

```pycon theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
>>> df = pd.DataFrame(
...     columns=["Desk", "Day", "Value"],
...     data=[
...         ("A", "Mon", 1),
...         ("A", "Tue", 2),
...         ("A", "Wed", 3),
...         ("B", "Mon", 10),
...         ("B", "Tue", 20),
...         ("C", "Mon", 100),
...         ("C", "Wed", 300),
...     ],
... )
>>> table = session.read_pandas(
...     df, keys={"Desk", "Day"}, table_name="Desk and day"
... )
>>> cube = session.create_cube(table)
>>> h, l, m = cube.hierarchies, cube.levels, cube.measures
>>> m["mode=measure"] = tt.shift(
...     m["Value.SUM"], h["Day"], offset=-1, mode="measure"
... )
>>> m["mode=hierarchy"] = tt.shift(
...     m["Value.SUM"], h["Day"], offset=-1, mode="hierarchy"
... )
>>> cube.query(
...     m["Value.SUM"],
...     m["mode=measure"],
...     m["mode=hierarchy"],
...     levels=[l["Day"], l["Desk"]],
...     include_totals=True,
... )
           Value.SUM mode=measure mode=hierarchy
Day   Desk
Total            436
Mon              111
      A            1
      B           10
      C          100
Tue               22          111            111
      A            2            1              1
      B           20           10             10
      C                                      100
Wed              303           22             22
      A            3            2              2
      B                                       20
      C          300          100
```

* `mode=measure`:
  * **(Tue, C)** and **(Wed, B)** have no values because **Value.SUM** also has no values at these locations.

    → The returned measure always evaluates to `None` where its input is also `None`.
  * **(Wed, C)** is `100` because shifting by *offset* `-1` along **Day** lands on **(Tue, C)** at which **Value.SUM** has no value so the shifting continues to the first non-`None` value: the one at **(Mon, C)**.

    → *offset* is lax.
* `mode=hierarchy`:
  * **(Tue, C)** is `100` even though **Value.SUM** has no value at this exact location because shifting by *offset* `-1` along **Day** lands on **(Mon, C)** which does have a value.

    → The returned measure evaluates to the input **measure**’s value at the shifted location, even where the input **measure** at the current location has no value.
  * **(Wed, C)** has no value because shifting by *offset* `-1` along **Day** lands on **(Tue, C)** at which **Value.SUM** has no value.

    → *offset* is strict.

***

<Callout icon="link">
  **See also**:
  [`date_shift()`](./atoti.function.date_shift#atoti.date_shift).
</Callout>
