Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pola-rs
GitHub Repository: pola-rs/polars
Path: blob/main/crates/polars-python/src/series/scatter.rs
8393 views
1
use arrow::array::Array;
2
use polars::prelude::*;
3
use polars_core::with_match_physical_numeric_polars_type;
4
use pyo3::prelude::*;
5
6
use super::PySeries;
7
use crate::utils::EnterPolarsExt;
8
9
#[pymethods]
10
impl PySeries {
11
fn scatter(&self, py: Python<'_>, idx: PySeries, values: PySeries) -> PyResult<()> {
12
py.enter_polars(|| {
13
// We take the value because we want a ref count of 1 so that we can
14
// have mutable access cheaply via _get_inner_mut().
15
let mut lock = self.series.write();
16
let s = std::mem::take(&mut *lock);
17
let result = scatter(s, &idx.series.into_inner(), &values.series.into_inner());
18
match result {
19
Ok(out) => {
20
*lock = out;
21
Ok(())
22
},
23
Err((s, e)) => {
24
*lock = s; // Restore original series.
25
Err(e)
26
},
27
}
28
})
29
}
30
}
31
32
fn scatter(s: Series, idx: &Series, values: &Series) -> Result<Series, (Series, PolarsError)> {
33
let logical_dtype = s.dtype().clone();
34
let converted_values;
35
let values = if logical_dtype.is_categorical() || logical_dtype.is_enum() {
36
if matches!(
37
values.dtype(),
38
DataType::Categorical(_, _) | DataType::Enum(_, _) | DataType::String | DataType::Null
39
) {
40
converted_values = values.strict_cast(&logical_dtype);
41
match converted_values {
42
Ok(ref values) => values,
43
Err(err) => return Err((s, err)),
44
}
45
} else {
46
return Err((
47
s,
48
polars_err!(InvalidOperation: "invalid values dtype '{}' for scattering into dtype '{}'", values.dtype(), logical_dtype),
49
));
50
}
51
} else if logical_dtype.is_decimal() {
52
if values.dtype().is_numeric() {
53
converted_values = values.strict_cast(&logical_dtype);
54
match converted_values {
55
Ok(ref values) => values,
56
Err(err) => return Err((s, err)),
57
}
58
} else {
59
return Err((
60
s,
61
polars_err!(InvalidOperation: "invalid values dtype '{}' for scattering into dtype '{}'", values.dtype(), logical_dtype),
62
));
63
}
64
} else {
65
values
66
};
67
68
let null_on_oob = false;
69
let idx = match polars_ops::prelude::convert_and_bound_index(idx, s.len(), null_on_oob) {
70
Ok(idx) => idx,
71
Err(err) => return Err((s, err)),
72
};
73
let idx = idx.rechunk();
74
let idx = idx.downcast_as_array();
75
if idx.has_nulls() {
76
return Err((
77
s,
78
PolarsError::ComputeError("index values should not be null".into()),
79
));
80
}
81
let idx = idx.values().as_slice();
82
83
let mut values = match values.to_physical_repr().cast(&s.dtype().to_physical()) {
84
Ok(values) => values,
85
Err(err) => return Err((s, err)),
86
};
87
88
// Broadcast values input.
89
if values.len() == 1 && idx.len() > 1 {
90
values = values.new_from_index(0, idx.len());
91
}
92
93
let mut phys = s.to_physical_repr().into_owned();
94
drop(s); // Reduce refcount to make use of in-place mutation of possible.
95
let ret = scatter_impl(&mut phys, &logical_dtype, idx, &values);
96
match ret {
97
Ok(s) => Ok(unsafe { s.from_physical_unchecked(&logical_dtype).unwrap() }),
98
Err(e) => Err((
99
unsafe { phys.from_physical_unchecked(&logical_dtype).unwrap() },
100
e,
101
)),
102
}
103
}
104
105
fn scatter_impl(
106
s: &mut Series,
107
logical_dtype: &DataType,
108
idx: &[IdxSize],
109
values: &Series,
110
) -> PolarsResult<Series> {
111
let mutable_s = s._get_inner_mut();
112
113
match mutable_s.dtype() {
114
dt if dt.is_primitive_numeric() => {
115
with_match_physical_numeric_polars_type!(dt, |$T| {
116
let ca: &mut ChunkedArray<$T> = mutable_s.as_mut();
117
let values: &ChunkedArray<$T> = values.as_ref().as_ref();
118
ca.scatter(idx, values)
119
})
120
},
121
DataType::Boolean => {
122
let ca: &mut ChunkedArray<BooleanType> = mutable_s.as_mut();
123
let values = values.bool()?;
124
ca.scatter(idx, values)
125
},
126
DataType::Binary => {
127
let ca: &mut ChunkedArray<BinaryType> = mutable_s.as_mut();
128
let values = values.binary()?;
129
ca.scatter(idx, values)
130
},
131
DataType::String => {
132
let ca: &mut ChunkedArray<StringType> = mutable_s.as_mut();
133
let values = values.str()?;
134
ca.scatter(idx, values)
135
},
136
_ => Err(PolarsError::ComputeError(
137
format!("not yet implemented for dtype: {logical_dtype}").into(),
138
)),
139
}
140
}
141
142