# ndaray is not c-contiguous

**URL:** <https://community.questdb.com/t/ndaray-is-not-c-contiguous/748>\
**Category:** Community\
**Created:** [February 13, 2025, 8:25am UTC](https://community.questdb.com/t/ndaray-is-not-c-contiguous/748 "2025-02-13T08:25:20Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![vtan](https://yyz2.discourse-cdn.com/flex004/user_avatar/community.questdb.com/vtan/32/352_2.png) [@vtan](https://community.questdb.com/u/vtan)\
**Post date:** [February 13, 2025, 8:25am UTC](https://community.questdb.com/t/ndaray-is-not-c-contiguous/748/1 "2025-02-13T08:25:20Z")

</div>

doing some benchmarking with quest using Python. Have below function to generate a dataframe.

def generate\_test\_data(iteration, columns):  
# Create a list of column names (just generic names ‘col\_0’, ‘col\_1’, …)  
col\_names = [f"col{i}" for i in range(columns)]

```
# Initialize the start time as current time
start_time = dt.datetime.now()

# Generate index as time series starting from current time, incremented by 1 ms
time_index = [start_time +
              dt.timedelta(milliseconds=i) for i in range(iteration)]

# Generate random data for the DataFrame (random floats in this case)
data = np.random.rand(iteration, columns)
data = np.asarray(data, order='C')
# Create DataFrame with generated time index
df = pd.DataFrame(data, columns=col_names, copy=True)
df['timestamp'] = time_index

print(df)
return df

```

The code to push into quest is pretty straight forward.

def write\_df(df: pd.DataFrame, table: str):  
with Sender.from\_conf(conf) as sender:  
sender.dataframe(  
df, table\_name=table, at=“timestamp”  
)

if the dimension is more than 1 column, i am getting

File “src/questdb/ingress.pyx”, line 2403, in questdb.ingress.Sender.dataframe  
File “src/questdb/dataframe.pxi”, line 2396, in questdb.ingress.\_dataframe  
File “src/questdb/dataframe.pxi”, line 2296, in questdb.ingress.\_dataframe  
File “src/questdb/dataframe.pxi”, line 1177, in questdb.ingress.\_dataframe\_resolve\_args  
File “src/questdb/dataframe.pxi”, line 1117, in questdb.ingress.\_dataframe\_resolve\_cols  
File “src/questdb/dataframe.pxi”, line 1017, in questdb.ingress.\_dataframe\_resolve\_source\_and\_buffers  
File “src/questdb/dataframe.pxi”, line 814, in questdb.ingress.\_dataframe\_series\_as\_pybuf  
questdb.ingress.IngressError: Bad column ‘col0’: ndarray is not C-contiguous

---

<div class="post-metadata">

**Author:** ![adamcimarosti](https://yyz2.discourse-cdn.com/flex004/user_avatar/community.questdb.com/adamcimarosti/32/339_2.png) [@adamcimarosti](https://community.questdb.com/u/adamcimarosti)\
**Post date:** [February 13, 2025, 4:41pm UTC](https://community.questdb.com/t/ndaray-is-not-c-contiguous/748/2 "2025-02-13T16:41:22Z")

</div>

> [@vtan](#):
>
> def generate\_test\_data(iteration, columns):
> 
> # Create a list of column names (just generic names ‘col\_0’, ‘col\_1’, …)
> 
> col\_names = [f"col{i}" for i in range(columns)]
> 
> ```auto
> # Initialize the start time as current time
> start_time = dt.datetime.now()
> 
> # Generate index as time series starting from current time, incremented by 1 ms
> time_index = [start_time +
> dt.timedelta(milliseconds=i) for i in range(iteration)]
> 
> # Generate random data for the DataFrame (random floats in this case)
> data = np.random.rand(iteration, columns)
> data = np.asarray(data, order='C')
> # Create DataFrame with generated time index
> df = pd.DataFrame(data, columns=col_names, copy=True)
> df['timestamp'] = time_index
> 
> print(df)
> return df
> 
> ```

As far as I can tell, you’re just after a test function.

Your existing logic generates a matrix in numpy and then slices it into pandas columns.  
Doing so, the memory of each column would not be contiguous: This is not something that we support in the `dataframe()` method as – in practice – one would generally create data for different columns independently.  
The columns in your code here are, as a result, strided (jump non-contiguously in memory from one element to the next).  
For your specific code, the fix is simple, you can generate the numpy array arranged as column-major (fortran style) rather than row-major (C style).  
In other words, changing `np.asarray(data, order='C')` to `np.asarray(data, order='F')`.

While you’re at it, you might want to avoid allocating Python objects when generating the timestamp column.

```python
start_time = pd.Timestamp.utcnow()
time_index = pd.date_range(start=start_time, periods=iteration, freq='1ms')

```

If you end up in this edge case again for other reasons, you can also flatten a numpy column to contiguous memory via [`np.ascontiguousarray(arr)`](https://numpy.org/doc/2.2/reference/generated/numpy.ascontiguousarray.html). Pandas operations themselves should never generate non-contiguous arrays.

Here is the updated code, populating a buffer:

```python
#!/usr/bin/env -S uv run --no-project

# /// script
# dependencies = ["questdb", "pandas", "numpy", "pyarrow"]
# ///

import questdb.ingress as qi
import numpy as np
import pandas as pd

def generate_test_data(iteration, columns):
    col_names = [f"col{i}" for i in range(columns)]
    start_time = pd.Timestamp.utcnow()
    time_index = pd.date_range(start=start_time, periods=iteration, freq='1ms')
    data = np.random.rand(iteration, columns)
    data = np.asarray(data, order='F')
    df = pd.DataFrame(data, columns=col_names, copy=True)
    df['timestamp'] = time_index
    print(df)
    return df

def main():
    df = generate_test_data(1000, 20)
    buf = qi.Buffer()
    buf.dataframe(df, table_name='foo', at='timestamp')

if __name__ == ' __main__':
    main()

```

I hope this helps.
