Repository: holoviz/datashader

Issue:
"Too many positional arguments" in pipeline when line_width>0
#### ALL software version info
datashader version 0.14.4

#### Description of expected behavior and the observed behavior
When setting non-zero line_width on `LineAxis0` glyphs (passed to `Pipeline`), an error is raised. With `set_line_width(0)`, or not calling `set_line_width` at all, it works fine.

In earlier versions (0.14.2 I think) `line_width>0` did not produce an error. However, it did not work correctly either (line width was respected but constant color/not shaded), which was why I tried to upgrade.

#### Complete, minimal, self-contained example code that reproduces the issue

```
import datashader as ds
import pandas as pd

df = pd.DataFrame(dict(x=[0,1],y=[0,1]))

glyph = ds.glyphs.LineAxis0('x','y')
glyph.set_line_width(1)
pipeline = ds.Pipeline(df, glyph)

pipeline(x_range=(0,1), y_range=(0,1), width=400, height=400)
```

#### Stack traceback and/or browser JavaScript console output

The stack is shown below, but the relevant bit seems to be:
```
too many positional arguments
During: resolving callee type: type(CPUDispatcher(<function append at 0x7f82b5fc9ab0>))
During: typing of call at <_full_antialias> (151)
```

Full trace:
```
---------------------------------------------------------------------------
TypingError                               Traceback (most recent call last)
Input In [5], in <cell line: 12>()
      8 dfs = pd.DataFrame(dict(x=[0,1],y=[0,1]))
     10 traj_pipeline = ds.Pipeline(dfs, glyph)#, color_fn=lambda agg: tf.shade(agg, cmap=cc.fire, how=cnorm, span=span))
---> 12 traj_pipeline(x_range=(0,1), y_range=(0,1), width=400, height=400)

File ~/mambaforge/envs/transact/lib/python3.10/site-packages/datashader/pipeline.py:69, in Pipeline.__call__(self, x_range, y_range, width, height)
     56 """Compute an image from the specified pipeline.
     57 
     58 Parameters
   (...)
     64     The shape of the image
     65 """
     66 canvas = core.Canvas(plot_width=int(width*self.width_scale),
     67                      plot_height=int(height*self.height_scale),
     68                      x_range=x_range, y_range=y_range)
---> 69 bins = core.bypixel(self.df, canvas, self.glyph, self.agg)
     70 img = self.color_fn(self.transform_fn(bins))
     71 return self.spread_fn(img)

File ~/mambaforge/envs/transact/lib/python3.10/site-packages/datashader/core.py:1260, in bypixel(source, canvas, glyph, agg, antialias)
   1258 with np.warnings.catch_warnings():
   1259     np.warnings.filterwarnings('ignore', r'All-NaN (slice|axis) encountered')
-> 1260     return bypixel.pipeline(source, schema, canvas, glyph, agg, antialias=antialias)

File ~/mambaforge/envs/transact/lib/python3.10/site-packages/datashader/utils.py:109, in Dispatcher.__call__(self, head, *rest, **kwargs)
    107 typ = type(head)
    108 if typ in lk:
--> 109     return lk[typ](head, *rest, **kwargs)
    110 for cls in getmro(typ)[1:]:
    111     if cls in lk:

File ~/mambaforge/envs/transact/lib/python3.10/site-packages/datashader/data_libraries/pandas.py:17, in pandas_pipeline(df, schema, canvas, glyph, summary, antialias)
     15 @bypixel.pipeline.register(pd.DataFrame)
     16 def pandas_pipeline(df, schema, canvas, glyph, summary, *, antialias=False):
---> 17     return glyph_dispatch(glyph, df, schema, canvas, summary, antialias=antialias)

File ~/mambaforge/envs/transact/lib/python3.10/site-packages/datashader/utils.py:112, in Dispatcher.__call__(self, head, *rest, **kwargs)
    110 for cls in getmro(typ)[1:]:
    111     if cls in lk:
--> 112         return lk[cls](head, *rest, **kwargs)
    113 raise TypeError("No dispatch for {0} type".format(typ))

File ~/mambaforge/envs/transact/lib/python3.10/site-packages/datashader/data_libraries/pandas.py:48, in default(glyph, source, schema, canvas, summary, antialias, cuda)
     44 y_axis = canvas.y_axis.compute_index(y_st, height)
     46 bases = create((height, width))
---> 48 extend(bases, source, x_st + y_st, x_range + y_range)
     50 return finalize(bases,
     51                 cuda=cuda,
     52                 coords=OrderedDict([(glyph.x_label, x_axis),
     53                                     (glyph.y_label, y_axis)]),
     54                 dims=[glyph.y_label, glyph.x_label])

File ~/mambaforge/envs/transact/lib/python3.10/site-packages/datashader/glyphs/line.py:110, in LineAxis0._internal_build_extend.<locals>.extend(aggs, df, vt, bounds, plot_start)
    107     do_extend = extend_cpu
    109 # line may be clipped, then mapped to pixels
--> 110 do_extend(
    111     sx, tx, sy, ty, xmin, xmax, ymin, ymax,
    112     xs, ys, plot_start, antialias_stage_2, *aggs_and_cols
    113 )

File ~/mambaforge/envs/transact/lib/python3.10/site-packages/numba/core/dispatcher.py:468, in _DispatcherBase._compile_for_args(self, *args, **kws)
    464         msg = (f"{str(e).rstrip()} \n\nThis error may have been caused "
    465                f"by the following argument(s):\n{args_str}\n")
    466         e.patch_message(msg)
--> 468     error_rewrite(e, 'typing')
    469 except errors.UnsupportedError as e:
    470     # Something unsupported is present in the user code, add help info
    471     error_rewrite(e, 'unsupported_error')

File ~/mambaforge/envs/transact/lib/python3.10/site-packages/numba/core/dispatcher.py:409, in _DispatcherBase._compile_for_args.<locals>.error_rewrite(e, issue_type)
    407     raise e
    408 else:
--> 409     raise e.with_traceback(None)

TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Failed in nopython mode pipeline (step: nopython frontend)
Failed in nopython mode pipeline (step: nopython frontend)
Failed in nopython mode pipeline (step: nopython frontend)
Internal error at <numba.core.typeinfer.CallConstraint object at 0x7f82b56daa10>.
too many positional arguments
During: resolving callee type: type(CPUDispatcher(<function append at 0x7f82b5fc9ab0>))
During: typing of call at <_full_antialias> (151)

Enable logging at debug level for details.

File "<_full_antialias>", line 151:
<source missing, REPL/exec in use?>

During: resolving callee type: type(CPUDispatcher(<function _full_antialias at 0x7f82b5ff9ab0>))
During: typing of call at <draw_segment> (47)

During: resolving callee type: type(CPUDispatcher(<function _full_antialias at 0x7f82b5ff9ab0>))
During: typing of call at <draw_segment> (47)


File "<draw_segment>", line 47:
<source missing, REPL/exec in use?>

During: resolving callee type: type(CPUDispatcher(<function draw_segment at 0x7f82b5ff9cf0>))
During: typing of call at <perform_extend_line> (21)

During: resolving callee type: type(CPUDispatcher(<function draw_segment at 0x7f82b5ff9cf0>))
During: typing of call at <perform_extend_line> (21)


File "<perform_extend_line>", line 21:
<source missing, REPL/exec in use?>

During: resolving callee type: type(CPUDispatcher(<function perform_extend_line at 0x7f82b5ff9e10>))
During: typing of call at <extend_cpu> (10)

During: resolving callee type: type(CPUDispatcher(<function perform_extend_line at 0x7f82b5ff9e10>))
During: typing of call at <extend_cpu> (10)


File "<extend_cpu>", line 10:
<source missing, REPL/exec in use?>
```


Discussion:
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/holoviz/datashader/pull/1213?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holoviz) Report
> Merging [#1213](https://app.codecov.io/gh/holoviz/datashader/pull/1213?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holoviz) (6fd8d37) into [main](https://app.codecov.io/gh/holoviz/datashader/commit/31b31826d74da38e4878f87c3e44511d08d302df?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holoviz) (31b3182) will **increase** coverage by `0.03%`.
> The diff coverage is `100.00%`.

```diff
@@            Coverage Diff             @@
##             main    #1213      +/-   ##
==========================================
+ Coverage   84.63%   84.66%   +0.03%     
==========================================
  Files          35       35              
  Lines        8354     8354              
==========================================
+ Hits         7070     7073       +3     
+ Misses       1284     1281       -3     
```


| [Impacted Files](https://app.codecov.io/gh/holoviz/datashader/pull/1213?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holoviz) | Coverage Δ | |
|---|---|---|
| [datashader/core.py](https://app.codecov.io/gh/holoviz/datashader/pull/1213?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holoviz#diff-ZGF0YXNoYWRlci9jb3JlLnB5) | `88.23% <ø> (-0.03%)` | :arrow_down: |
| [datashader/glyphs/line.py](https://app.codecov.io/gh/holoviz/datashader/pull/1213?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holoviz#diff-ZGF0YXNoYWRlci9nbHlwaHMvbGluZS5weQ==) | `93.05% <100.00%> (+0.20%)` | :arrow_up: |
| [datashader/pipeline.py](https://app.codecov.io/gh/holoviz/datashader/pull/1213?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holoviz#diff-ZGF0YXNoYWRlci9waXBlbGluZS5weQ==) | `100.00% <100.00%> (ø)` | |

... and [1 file with indirect coverage changes](https://app.codecov.io/gh/holoviz/datashader/pull/1213/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holoviz)

:mega: We’re building smart automated test selection to slash your CI/CD build times. [Learn more](https://about.codecov.io/iterative-testing/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holoviz)


Patch:
diff --git a/datashader/compiler.py b/datashader/compiler.py
index bc27c73..8e3f9ee 100644
--- a/datashader/compiler.py
+++ b/datashader/compiler.py
@@ -32,7 +32,7 @@ def compile_components(agg, schema, glyph, *, antialias=False, cuda=False):
         Takes the aggregate shape, and returns a tuple of initialized numpy
         arrays.
 
-    ``info(df)``
+    ``info(df, canvas_shape)``
         Takes a dataframe, and returns preprocessed 1D numpy arrays of the
         needed columns.
 
@@ -45,7 +45,7 @@ def compile_components(agg, schema, glyph, *, antialias=False, cuda=False):
         Combine a list of base tuples into a single base tuple. This forms the
         reducing step in a reduction tree.
 
-    ``finalize(aggs)``
+    ``finalize(aggs, cuda)``
         Given a tuple of base numpy arrays, returns the finalized ``DataArray``
         or ``Dataset``.
 
@@ -128,11 +128,16 @@ def make_create(bases, dshapes, cuda):
 
 
 def make_info(cols, uses_cuda_mutex):
-    def info(df):
+    def info(df, canvas_shape):
         ret = tuple(c.apply(df) for c in cols)
         if uses_cuda_mutex:
             import cupy  # Guaranteed to be available if uses_cuda_mutex is True
-            mutex_array = cupy.zeros((1,), dtype=np.uint32)
+            import numba
+            from packaging.version import Version
+            if Version(numba.__version__) >= Version("0.57"):
+                mutex_array = cupy.zeros(canvas_shape, dtype=np.uint32)
+            else:
+                mutex_array = cupy.zeros((1,), dtype=np.uint32)
             ret += (mutex_array,)
         return ret
 
diff --git a/datashader/core.py b/datashader/core.py
index 5e6cdc8..2a7b845 100644
--- a/datashader/core.py
+++ b/datashader/core.py
@@ -431,7 +431,6 @@ The axis argument to Canvas.line must be 0 or 1
             line_width = 0
 
         glyph.set_line_width(line_width)
-        glyph.antialiased = (line_width > 0)
 
         if glyph.antialiased:
             # This is required to identify and report use of reductions that do
diff --git a/datashader/glyphs/area.py b/datashader/glyphs/area.py
index 27ae90d..4cd5e63 100644
--- a/datashader/glyphs/area.py
+++ b/datashader/glyphs/area.py
@@ -114,7 +114,7 @@ class AreaToZeroAxis0(_PointLike):
         def extend(aggs, df, vt, bounds, plot_start=True):
             sx, tx, sy, ty = vt
             xmin, xmax, ymin, ymax = bounds
-            aggs_and_cols = aggs + info(df)
+            aggs_and_cols = aggs + info(df, aggs[0].shape[:2])
 
             if cudf and isinstance(df, cudf.DataFrame):
                 xs = self.to_cupy_array(df, x_name)
@@ -198,7 +198,7 @@ class AreaToLineAxis0(_AreaToLineLike):
         def extend(aggs, df, vt, bounds, plot_start=True):
             sx, tx, sy, ty = vt
             xmin, xmax, ymin, ymax = bounds
-            aggs_and_cols = aggs + info(df)
+            aggs_and_cols = aggs + info(df, aggs[0].shape[:2])
 
             if cudf and isinstance(df, cudf.DataFrame):
                 xs = self.to_cupy_array(df, x_name)
@@ -290,7 +290,7 @@ class AreaToZeroAxis0Multi(_PointLike):
         def extend(aggs, df, vt, bounds, plot_start=True):
             sx, tx, sy, ty = vt
             xmin, xmax, ymin, ymax = bounds
-            aggs_and_cols = aggs + info(df)
+            aggs_and_cols = aggs + info(df, aggs[0].shape[:2])
 
             if cudf and isinstance(df, cudf.DataFrame):
                 xs = self.to_cupy_array(df, x_names)
@@ -381,7 +381,7 @@ class AreaToLineAxis0Multi(_AreaToLineLike):
         def extend(aggs, df, vt, bounds, plot_start=True):
             sx, tx, sy, ty = vt
             xmin, xmax, ymin, ymax = bounds
-            aggs_and_cols = aggs + info(df)
+            aggs_and_cols = aggs + info(df, aggs[0].shape[:2])
 
             if cudf and isinstance(df, cudf.DataFrame):
                 xs = self.to_cupy_array(df, x_names)
@@ -489,7 +489,7 @@ class AreaToZeroAxis1(_PointLike):
         def extend(aggs, df, vt, bounds, plot_start=True):
             sx, tx, sy, ty = vt
             xmin, xmax, ymin, ymax = bounds
-            aggs_and_cols = aggs + info(df)
+            aggs_and_cols = aggs + info(df, aggs[0].shape[:2])
 
             if cudf and isinstance(df, cudf.DataFrame):
                 xs = self.to_cupy_array(df,list(x_names))
@@ -596,7 +596,7 @@ class AreaToLineAxis1(_AreaToLineLike):
         def extend(aggs, df, vt, bounds, plot_start=True):
             sx, tx, sy, ty = vt
             xmin, xmax, ymin, ymax = bounds
-            aggs_and_cols = aggs + info(df)
+            aggs_and_cols = aggs + info(df, aggs[0].shape[:2])
 
             if cudf and isinstance(df, cudf.DataFrame):
                 xs = self.to_cupy_array(df,list(x_names))
@@ -665,7 +665,7 @@ class AreaToZeroAxis1XConstant(AreaToZeroAxis1):
         def extend(aggs, df, vt, bounds, plot_start=True):
             sx, tx, sy, ty = vt
             xmin, xmax, ymin, ymax = bounds
-            aggs_and_cols = aggs + info(df)
+            aggs_and_cols = aggs + info(df, aggs[0].shape[:2])
 
             if cudf and isinstance(df, cudf.DataFrame):
                 ys = self.to_cupy_array(df,list(y_names))
@@ -745,7 +745,7 @@ class AreaToLineAxis1XConstant(AreaToLineAxis1):
         def extend(aggs, df, vt, bounds, plot_start=True):
             sx, tx, sy, ty = vt
             xmin, xmax, ymin, ymax = bounds
-            aggs_and_cols = aggs + info(df)
+            aggs_and_cols = aggs + info(df, aggs[0].shape[:2])
 
             if cudf and isinstance(df, cudf.DataFrame):
                 ys = self.to_cupy_array(df,list(y_names))
@@ -813,7 +813,7 @@ class AreaToZeroAxis1YConstant(AreaToZeroAxis1):
         def extend(aggs, df, vt, bounds, plot_start=True):
             sx, tx, sy, ty = vt
             xmin, xmax, ymin, ymax = bounds
-            aggs_and_cols = aggs + info(df)
+            aggs_and_cols = aggs + info(df, aggs[0].shape[:2])
 
             if cudf and isinstance(df, cudf.DataFrame):
                 xs = self.to_cupy_array(df,list(x_names))
@@ -881,7 +881,7 @@ class AreaToLineAxis1YConstant(AreaToLineAxis1):
         def extend(aggs, df, vt, bounds, plot_start=True):
             sx, tx, sy, ty = vt
             xmin, xmax, ymin, ymax = bounds
-            aggs_and_cols = aggs + info(df)
+            aggs_and_cols = aggs + info(df, aggs[0].shape[:2])
 
             if cudf and isinstance(df, cudf.DataFrame):
                 xs = self.to_cupy_array(df,list(x_names))
@@ -968,7 +968,7 @@ class AreaToZeroAxis1Ragged(_PointLike):
 
             xs = df[x_name].values
             ys = df[y_name].values
-            aggs_and_cols = aggs + info(df)
+            aggs_and_cols = aggs + info(df, aggs[0].shape[:2])
             perform_extend_cpu(
                 sx, tx, sy, ty,
                 xmin, xmax, ymin, ymax,
@@ -1051,7 +1051,7 @@ class AreaToLineAxis1Ragged(_AreaToLineLike):
             ys = df[y_name].values
             y_stacks = df[y_stack_name].values
 
-            aggs_and_cols = aggs + info(df)
+            aggs_and_cols = aggs + info(df, aggs[0].shape[:2])
             extend_cpu(
                 sx, tx, sy, ty,
                 xmin, xmax, ymin, ymax,
diff --git a/datashader/glyphs/line.py b/datashader/glyphs/line.py
index c1e42fd..fbfe6b2 100644
--- a/datashader/glyphs/line.py
+++ b/datashader/glyphs/line.py
@@ -61,6 +61,8 @@ class _AntiAliasedLine(object):
 
     def set_line_width(self, line_width):
         self._line_width = line_width
+        if hasattr(self, "antialiased"):
+            self.antialiased = (line_width > 0)
 
     def _build_extend(self, x_mapper, y_mapper, info, append, antialias_stage_2):
         return self._internal_build_extend(
@@ -95,7 +97,7 @@ class LineAxis0(_PointLike, _AntiAliasedLine):
         def extend(aggs, df, vt, bounds, plot_start=True):
             sx, tx, sy, ty = vt
             xmin, xmax, ymin, ymax = bounds
-            aggs_and_cols = aggs + info(df)
+            aggs_and_cols = aggs + info(df, aggs[0].shape[:2])
 
             if cudf and isinstance(df, cudf.DataFrame):
                 xs = self.to_cupy_array(df, x_name)
@@ -189,7 +191,7 @@ class LineAxis0Multi(_PointLike, _AntiAliasedLine):
         def extend(aggs, df, vt, bounds, plot_start=True):
             sx, tx, sy, ty = vt
             xmin, xmax, ymin, ymax = bounds
-            aggs_and_cols = aggs + info(df)
+            aggs_and_cols = aggs + info(df, aggs[0].shape[:2])
 
             if cudf and isinstance(df, cudf.DataFrame):
                 xs = self.to_cupy_array(df, x_names)
@@ -304,7 +306,7 @@ class LinesAxis1(_PointLike, _AntiAliasedLine):
         def extend(aggs, df, vt, bounds, plot_start=True):
             sx, tx, sy, ty = vt
             xmin, xmax, ymin, ymax = bounds
-            aggs_and_cols = aggs + info(df)
+            aggs_and_cols = aggs + info(df, aggs[0].shape[:2])
 
             if cudf and isinstance(df, cudf.DataFrame):
                 xs = self.to_cupy_array(df, x_names)
@@ -380,7 +382,7 @@ class LinesAxis1XConstant(LinesAxis1):
         def extend(aggs, df, vt, bounds, plot_start=True):
             sx, tx, sy, ty = vt
             xmin, xmax, ymin, ymax = bounds
-            aggs_and_cols = aggs + info(df)
+            aggs_and_cols = aggs + info(df, aggs[0].shape[:2])
 
             if cudf and isinstance(df, cudf.DataFrame):
                 xs = cp.asarray(x_values)
@@ -456,7 +458,7 @@ class LinesAxis1YConstant(LinesAxis1):
         def extend(aggs, df, vt, bounds, plot_start=True):
             sx, tx, sy, ty = vt
             xmin, xmax, ymin, ymax = bounds
-            aggs_and_cols = aggs + info(df)
+            aggs_and_cols = aggs + info(df, aggs[0].shape[:2])
 
             if cudf and isinstance(df, cudf.DataFrame):
                 xs = self.to_cupy_array(df, x_names)
@@ -536,7 +538,7 @@ class LinesAxis1Ragged(_PointLike, _AntiAliasedLine):
             xs = df[x_name].array
             ys = df[y_name].array
 
-            aggs_and_cols = aggs + info(df)
+            aggs_and_cols = aggs + info(df, aggs[0].shape[:2])
             # line may be clipped, then mapped to pixels
             extend_cpu(
                 sx, tx, sy, ty, xmin, xmax, ymin, ymax, xs, ys, antialias_stage_2, *aggs_and_cols
@@ -579,7 +581,7 @@ class LineAxis1Geometry(_GeometryLike, _AntiAliasedLine):
         def extend(aggs, df, vt, bounds, plot_start=True):
             sx, tx, sy, ty = vt
             xmin, xmax, ymin, ymax = bounds
-            aggs_and_cols = aggs + info(df)
+            aggs_and_cols = aggs + info(df, aggs[0].shape[:2])
             geom_array = df[geometry_name].array
 
             # Use type to decide whether geometry represents a closed .
diff --git a/datashader/glyphs/points.py b/datashader/glyphs/points.py
index 16a9b6f..c30af28 100644
--- a/datashader/glyphs/points.py
+++ b/datashader/glyphs/points.py
@@ -199,7 +199,7 @@ class Point(_PointLike):
 
         def extend(aggs, df, vt, bounds):
             yymax, xxmax = aggs[0].shape[:2]
-            aggs_and_cols = aggs + info(df)
+            aggs_and_cols = aggs + info(df, aggs[0].shape[:2])
             sx, tx, sy, ty = vt
             xmin, xmax, ymin, ymax = bounds
 
@@ -282,7 +282,7 @@ class MultiPointGeometry(_GeometryLike):
         def extend(aggs, df, vt, bounds):
             from spatialpandas.geometry import PointArray
 
-            aggs_and_cols = aggs + info(df)
+            aggs_and_cols = aggs + info(df, aggs[0].shape[:2])
             sx, tx, sy, ty = vt
             xmin, xmax, ymin, ymax = bounds
 
diff --git a/datashader/glyphs/polygon.py b/datashader/glyphs/polygon.py
index 4a9a536..f296b14 100644
--- a/datashader/glyphs/polygon.py
+++ b/datashader/glyphs/polygon.py
@@ -35,7 +35,7 @@ class PolygonGeom(_GeometryLike):
         def extend(aggs, df, vt, bounds, plot_start=True):
             sx, tx, sy, ty = vt
             xmin, xmax, ymin, ymax = bounds
-            aggs_and_cols = aggs + info(df)
+            aggs_and_cols = aggs + info(df, aggs[0].shape[:2])
             geom_array = df[geom_name].array
 
             perform_extend_cpu(
diff --git a/datashader/glyphs/quadmesh.py b/datashader/glyphs/quadmesh.py
index 4d7d2b7..192e633 100644
--- a/datashader/glyphs/quadmesh.py
+++ b/datashader/glyphs/quadmesh.py
@@ -204,7 +204,7 @@ class QuadMeshRectilinear(_QuadMeshLike):
             ys = (yscaled[ym0:ym1 + 1] * plot_height).astype(int).clip(0, plot_height)
 
             # For input "column", down select to valid range
-            cols_full = info(xr_ds.transpose(y_name, x_name))
+            cols_full = info(xr_ds.transpose(y_name, x_name), aggs[0].shape[:2])
             cols = tuple([c[ym0:ym1, xm0:xm1] for c in cols_full])
 
             aggs_and_cols = aggs + cols
@@ -378,7 +378,7 @@ class QuadMeshRaster(QuadMeshRectilinear):
                 offset_x = offset_y = 0
 
             # Build aggs_and_cols tuple
-            cols = info(xr_ds)
+            cols = info(xr_ds, aggs[0].shape[:2])
             aggs_and_cols = tuple(aggs) + tuple(cols)
 
             if src_h == 0 or src_w == 0 or out_h == 0 or out_w == 0:
@@ -660,7 +660,7 @@ class QuadMeshCurvilinear(_QuadMeshLike):
             ys = (yscaled * plot_height).astype(int)
 
             coord_dims = xr_ds.coords[x_name].dims
-            aggs_and_cols = aggs + info(xr_ds.transpose(*coord_dims))
+            aggs_and_cols = aggs + info(xr_ds.transpose(*coord_dims), aggs[0].shape[:2])
             if use_cuda:
                 do_extend = extend_cuda[cuda_args(xr_ds[name].shape)]
             else:
diff --git a/datashader/glyphs/trimesh.py b/datashader/glyphs/trimesh.py
index c24daf1..83f74a3 100644
--- a/datashader/glyphs/trimesh.py
+++ b/datashader/glyphs/trimesh.py
@@ -70,7 +70,7 @@ class Triangles(_PolygonLike):
         interpolate = self.interpolate
 
         def extend(aggs, df, vt, bounds, plot_start=True):
-            cols = info(df)
+            cols = info(df, aggs[0].shape[:2])
             assert cols, 'There must be at least one column on which to aggregate'
             # mapped to pixels, then may be clipped
             extend_triangles(vt, bounds, df.values, weight_type, interpolate, aggs, cols)
diff --git a/datashader/pipeline.py b/datashader/pipeline.py
index 6be86a7..96e9b26 100644
--- a/datashader/pipeline.py
+++ b/datashader/pipeline.py
@@ -66,6 +66,7 @@ class Pipeline(object):
         canvas = core.Canvas(plot_width=int(width*self.width_scale),
                              plot_height=int(height*self.height_scale),
                              x_range=x_range, y_range=y_range)
-        bins = core.bypixel(self.df, canvas, self.glyph, self.agg)
+        bins = core.bypixel(self.df, canvas, self.glyph, self.agg,
+                            antialias=self.glyph.antialiased)
         img = self.color_fn(self.transform_fn(bins))
         return self.spread_fn(img)
diff --git a/datashader/reductions.py b/datashader/reductions.py
index be974a4..6d09307 100644
--- a/datashader/reductions.py
+++ b/datashader/reductions.py
@@ -1359,7 +1359,7 @@ class max_n(FloatingNReduction):
             # Linear walk along stored values.
             # Could do binary search instead but not expecting n to be large.
             n = agg.shape[2]
-            index = (x, y)
+            index = (y, x)
             cuda_mutex_lock(mutex, index)
             for i in range(n):
                 if isnull(agg[y, x, i]) or field > agg[y, x, i]:
@@ -1430,7 +1430,7 @@ class min_n(FloatingNReduction):
             # Linear walk along stored values.
             # Could do binary search instead but not expecting n to be large.
             n = agg.shape[2]
-            index = (x, y)
+            index = (y, x)
             cuda_mutex_lock(mutex, index)
             for i in range(n):
                 if isnull(agg[y, x, i]) or field < agg[y, x, i]:
diff --git a/datashader/transfer_functions/_cuda_utils.py b/datashader/transfer_functions/_cuda_utils.py
index 3238247..5078a30 100644
--- a/datashader/transfer_functions/_cuda_utils.py
+++ b/datashader/transfer_functions/_cuda_utils.py
@@ -173,17 +173,29 @@ def interp2d_kernel(x, xp, fp, left, right, output_y):
             output_y[i, j] = y_interp
 
 
-@cuda.jit(device=True)
-def cuda_mutex_lock(mutex, index):
-    while cuda.atomic.compare_and_swap(mutex, 0, 1) != 0:
-          pass
-    cuda.threadfence()
+if Version(numba.__version__) >= Version("0.57"):
+    # See issues #1196 and #1211.
+    @cuda.jit(device=True)
+    def cuda_mutex_lock(mutex, index):
+        while cuda.atomic.cas(mutex, index, 0, 1) != 0:
+            pass
+        cuda.threadfence()
 
+    @cuda.jit(device=True)
+    def cuda_mutex_unlock(mutex, index):
+        cuda.threadfence()
+        cuda.atomic.exch(mutex, index, 0)
+else:
+    @cuda.jit(device=True)
+    def cuda_mutex_lock(mutex, index):
+        while cuda.atomic.compare_and_swap(mutex, 0, 1) != 0:
+              pass
+        cuda.threadfence()
 
-@cuda.jit(device=True)
-def cuda_mutex_unlock(mutex, index):
-    cuda.threadfence()
-    cuda.atomic.exch(mutex, 0, 0)
+    @cuda.jit(device=True)
+    def cuda_mutex_unlock(mutex, index):
+        cuda.threadfence()
+        cuda.atomic.exch(mutex, 0, 0)
 
 
 @cuda.jit


Test patch:
diff --git a/datashader/tests/test_pipeline.py b/datashader/tests/test_pipeline.py
index 5085f7a..3df9289 100644
--- a/datashader/tests/test_pipeline.py
+++ b/datashader/tests/test_pipeline.py
@@ -1,6 +1,7 @@
 from __future__ import annotations
 import numpy as np
 import pandas as pd
+import pytest
 import datashader as ds
 import datashader.transfer_functions as tf
 
@@ -11,6 +12,7 @@ df = pd.DataFrame({'x': np.array(([0.] * 10 + [1] * 10)),
 df.f64.iloc[2] = np.nan
 
 cvs = ds.Canvas(plot_width=2, plot_height=2, x_range=(0, 1), y_range=(0, 1))
+cvs10 = ds.Canvas(plot_width=10, plot_height=10, x_range=(0, 1), y_range=(0, 1))
 
 
 def test_pipeline():
@@ -33,3 +35,18 @@ def test_pipeline():
     img = pipeline((0, 1), (0, 1), 2, 2)
     agg = cvs.points(df, 'x', 'y', ds.sum('f64'))
     assert img.equals(tf.shade(agg))
+
+
+@pytest.mark.parametrize("line_width", [0.0, 0.5, 1.0, 2.0])
+def test_pipeline_antialias(line_width):
+    glyph = ds.glyphs.LineAxis0('x', 'y')
+
+    glyph.set_line_width(line_width=line_width)
+    assert glyph._line_width == line_width
+    assert glyph.antialiased == (line_width > 0)
+
+    pipeline = ds.Pipeline(df, glyph)
+    img = pipeline(width=cvs10.plot_width, height=cvs10.plot_height,
+                   x_range=cvs10.x_range, y_range=cvs10.y_range)
+    agg = cvs10.line(df, 'x', 'y', agg=ds.reductions.count(), line_width=line_width)
+    assert img.equals(tf.dynspread(tf.shade(agg)))