diff --git a/.github/ops-bot.yaml b/.github/ops-bot.yaml index 9a0b4155..2ed5231a 100644 --- a/.github/ops-bot.yaml +++ b/.github/ops-bot.yaml @@ -6,3 +6,4 @@ branch_checker: true label_checker: true release_drafter: true recently_updated: true +forward_merger: true diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index db2c6d70..faae9637 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -28,7 +28,7 @@ concurrency: jobs: python-build: secrets: inherit - uses: rapidsai/shared-workflows/.github/workflows/conda-python-build.yaml@branch-24.02 + uses: rapidsai/shared-workflows/.github/workflows/conda-python-build.yaml@branch-24.04 with: build_type: ${{ inputs.build_type || 'branch' }} branch: ${{ inputs.branch }} @@ -37,7 +37,7 @@ jobs: upload-conda: needs: [python-build] secrets: inherit - uses: rapidsai/shared-workflows/.github/workflows/conda-upload-packages.yaml@branch-24.02 + uses: rapidsai/shared-workflows/.github/workflows/conda-upload-packages.yaml@branch-24.04 with: build_type: ${{ inputs.build_type || 'branch' }} branch: ${{ inputs.branch }} @@ -47,7 +47,7 @@ jobs: if: github.ref_type == 'branch' needs: python-build secrets: inherit - uses: rapidsai/shared-workflows/.github/workflows/custom-job.yaml@branch-24.02 + uses: rapidsai/shared-workflows/.github/workflows/custom-job.yaml@branch-24.04 with: arch: "amd64" branch: ${{ inputs.branch }} @@ -59,18 +59,19 @@ jobs: sha: ${{ inputs.sha }} wheel-build: secrets: inherit - uses: rapidsai/shared-workflows/.github/workflows/wheels-build.yaml@branch-24.02 + uses: rapidsai/shared-workflows/.github/workflows/wheels-build.yaml@branch-24.04 with: build_type: ${{ inputs.build_type || 'branch' }} branch: ${{ inputs.branch }} sha: ${{ inputs.sha }} date: ${{ inputs.date }} script: ci/build_wheel.sh - matrix_filter: map(select(.ARCH == "amd64" and .PY_VER == "3.10" and (.CUDA_VER == "11.8.0" or .CUDA_VER == "12.0.1"))) + # This selects "ARCH=amd64 + the latest supported Python + CUDA". + matrix_filter: map(select(.ARCH == "amd64")) | max_by([(.PY_VER|split(".")|map(tonumber)), (.CUDA_VER|split(".")|map(tonumber))]) | [.] wheel-publish: needs: wheel-build secrets: inherit - uses: rapidsai/shared-workflows/.github/workflows/wheels-publish.yaml@branch-24.02 + uses: rapidsai/shared-workflows/.github/workflows/wheels-publish.yaml@branch-24.04 with: build_type: ${{ inputs.build_type || 'branch' }} branch: ${{ inputs.branch }} diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index ba7ed908..87e5e75d 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -20,27 +20,27 @@ jobs: - wheel-build - wheel-tests secrets: inherit - uses: rapidsai/shared-workflows/.github/workflows/pr-builder.yaml@branch-24.02 + uses: rapidsai/shared-workflows/.github/workflows/pr-builder.yaml@branch-24.04 checks: secrets: inherit - uses: rapidsai/shared-workflows/.github/workflows/checks.yaml@branch-24.02 + uses: rapidsai/shared-workflows/.github/workflows/checks.yaml@branch-24.04 conda-python-build: needs: checks secrets: inherit - uses: rapidsai/shared-workflows/.github/workflows/conda-python-build.yaml@branch-24.02 + uses: rapidsai/shared-workflows/.github/workflows/conda-python-build.yaml@branch-24.04 with: build_type: pull-request conda-python-tests: needs: conda-python-build secrets: inherit - uses: rapidsai/shared-workflows/.github/workflows/conda-python-tests.yaml@branch-24.02 + uses: rapidsai/shared-workflows/.github/workflows/conda-python-tests.yaml@branch-24.04 with: build_type: pull-request run_codecov: false conda-notebook-tests: needs: conda-python-build secrets: inherit - uses: rapidsai/shared-workflows/.github/workflows/custom-job.yaml@branch-24.02 + uses: rapidsai/shared-workflows/.github/workflows/custom-job.yaml@branch-24.04 with: build_type: pull-request node_type: "gpu-v100-latest-1" @@ -50,7 +50,7 @@ jobs: docs-build: needs: conda-python-build secrets: inherit - uses: rapidsai/shared-workflows/.github/workflows/custom-job.yaml@branch-24.02 + uses: rapidsai/shared-workflows/.github/workflows/custom-job.yaml@branch-24.04 with: build_type: pull-request node_type: "gpu-v100-latest-1" @@ -60,16 +60,18 @@ jobs: wheel-build: needs: checks secrets: inherit - uses: rapidsai/shared-workflows/.github/workflows/wheels-build.yaml@branch-24.02 + uses: rapidsai/shared-workflows/.github/workflows/wheels-build.yaml@branch-24.04 with: build_type: pull-request script: ci/build_wheel.sh - matrix_filter: map(select(.ARCH == "amd64" and .PY_VER == "3.10" and (.CUDA_VER == "11.8.0" or .CUDA_VER == "12.0.1"))) + # This selects "ARCH=amd64 + the latest supported Python + CUDA". + matrix_filter: map(select(.ARCH == "amd64")) | max_by([(.PY_VER|split(".")|map(tonumber)), (.CUDA_VER|split(".")|map(tonumber))]) | [.] wheel-tests: needs: wheel-build secrets: inherit - uses: rapidsai/shared-workflows/.github/workflows/wheels-test.yaml@branch-24.02 + uses: rapidsai/shared-workflows/.github/workflows/wheels-test.yaml@branch-24.04 with: build_type: pull-request script: ci/test_wheel.sh - matrix_filter: map(select(.ARCH == "amd64" and .PY_VER == "3.10" and (.CUDA_VER == "11.8.0" or .CUDA_VER == "12.0.1"))) + # This selects "ARCH=amd64 + the latest supported Python + CUDA". + matrix_filter: map(select(.ARCH == "amd64")) | max_by([(.PY_VER|split(".")|map(tonumber)), (.CUDA_VER|split(".")|map(tonumber))]) | [.] diff --git a/.github/workflows/test-external.yaml b/.github/workflows/test-external.yaml index 06e503de..37c0c6af 100644 --- a/.github/workflows/test-external.yaml +++ b/.github/workflows/test-external.yaml @@ -23,7 +23,7 @@ on: jobs: test-external: secrets: inherit - uses: rapidsai/shared-workflows/.github/workflows/custom-job.yaml@branch-24.02 + uses: rapidsai/shared-workflows/.github/workflows/custom-job.yaml@branch-24.04 with: build_type: branch node_type: "gpu-v100-latest-1" diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 22ba5dd4..31e0c29e 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -16,7 +16,7 @@ on: jobs: conda-python-tests: secrets: inherit - uses: rapidsai/shared-workflows/.github/workflows/conda-python-tests.yaml@branch-24.02 + uses: rapidsai/shared-workflows/.github/workflows/conda-python-tests.yaml@branch-24.04 with: build_type: nightly branch: ${{ inputs.branch }} @@ -24,11 +24,12 @@ jobs: sha: ${{ inputs.sha }} wheel-tests: secrets: inherit - uses: rapidsai/shared-workflows/.github/workflows/wheels-test.yaml@branch-24.02 + uses: rapidsai/shared-workflows/.github/workflows/wheels-test.yaml@branch-24.04 with: build_type: nightly branch: ${{ inputs.branch }} date: ${{ inputs.date }} sha: ${{ inputs.sha }} script: ci/test_wheel.sh - matrix_filter: map(select(.ARCH == "amd64" and .PY_VER == "3.10" and (.CUDA_VER == "11.8.0" or .CUDA_VER == "12.0.1"))) + # This selects "ARCH=amd64 + the latest supported Python + CUDA". + matrix_filter: map(select(.ARCH == "amd64")) | max_by([(.PY_VER|split(".")|map(tonumber)), (.CUDA_VER|split(".")|map(tonumber))]) | [.] diff --git a/CHANGELOG.md b/CHANGELOG.md index 70bb9b75..81f2b9d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,32 @@ +# cuXfilter 24.04.00 (10 Apr 2024) + +## 🐛 Bug Fixes + +- [Ready for Review] Pandas 2.0 compatibility ([#569](https://github.com/rapidsai/cuxfilter/pull/569)) [@AjayThorve](https://github.com/AjayThorve) +- handle more RAPIDS version formats in update-version.sh ([#566](https://github.com/rapidsai/cuxfilter/pull/566)) [@jameslamb](https://github.com/jameslamb) + +## 📖 Documentation + +- Remove hard-coding of RAPIDS version where possible ([#579](https://github.com/rapidsai/cuxfilter/pull/579)) [@KyleFromNVIDIA](https://github.com/KyleFromNVIDIA) + +## 🚀 New Features + +- Support CUDA 12.2 ([#563](https://github.com/rapidsai/cuxfilter/pull/563)) [@jameslamb](https://github.com/jameslamb) + +## 🛠️ Improvements + +- Use `conda env create --yes` instead of `--force` ([#584](https://github.com/rapidsai/cuxfilter/pull/584)) [@bdice](https://github.com/bdice) +- add option to enable/disable axes ([#581](https://github.com/rapidsai/cuxfilter/pull/581)) [@AjayThorve](https://github.com/AjayThorve) +- Add upper bound to prevent usage of NumPy 2 ([#580](https://github.com/rapidsai/cuxfilter/pull/580)) [@bdice](https://github.com/bdice) +- Use public cudf APIs where possible ([#578](https://github.com/rapidsai/cuxfilter/pull/578)) [@mroeschke](https://github.com/mroeschke) +- Treat cuxfilter CI artifacts as pure wheels ([#577](https://github.com/rapidsai/cuxfilter/pull/577)) [@bdice](https://github.com/bdice) +- Switch `pytest-xdist` algorithm to `worksteal` ([#576](https://github.com/rapidsai/cuxfilter/pull/576)) [@bdice](https://github.com/bdice) +- Generalize GHA selectors for pure Python testing ([#575](https://github.com/rapidsai/cuxfilter/pull/575)) [@jakirkham](https://github.com/jakirkham) +- Requre NumPy 1.23+ ([#574](https://github.com/rapidsai/cuxfilter/pull/574)) [@jakirkham](https://github.com/jakirkham) +- Add support for Python 3.11 ([#572](https://github.com/rapidsai/cuxfilter/pull/572)) [@jameslamb](https://github.com/jameslamb) +- target branch-24.04 for GitHub Actions workflows ([#571](https://github.com/rapidsai/cuxfilter/pull/571)) [@jameslamb](https://github.com/jameslamb) +- Update ops-bot.yaml ([#568](https://github.com/rapidsai/cuxfilter/pull/568)) [@AyodeAwe](https://github.com/AyodeAwe) + # cuXfilter 24.02.00 (12 Feb 2024) ## 🐛 Bug Fixes diff --git a/README.md b/README.md index 248b1d78..4c3565cf 100644 --- a/README.md +++ b/README.md @@ -153,16 +153,16 @@ Please see the [Demo Docker Repository](https://hub.docker.com/r/rapidsai/rapids cuxfilter can be installed with conda ([miniconda](https://conda.io/miniconda.html), or the full [Anaconda distribution](https://www.anaconda.com/download)) from the `rapidsai` channel: -For nightly version `cuxfilter version == 24.02` : +For nightly version `cuxfilter version == 24.04` : ```bash # for CUDA 12.0 conda install -c rapidsai-nightly -c conda-forge -c nvidia \ - cuxfilter=24.02 python=3.10 cuda-version=12.0 + cuxfilter=24.04 python=3.11 cuda-version=12.0 # for CUDA 11.8 conda install -c rapidsai-nightly -c conda-forge -c nvidia \ - cuxfilter=24.02 python=3.10 cuda-version=11.8 + cuxfilter=24.04 python=3.11 cuda-version=11.8 ``` For the stable version of `cuxfilter` : @@ -170,11 +170,11 @@ For the stable version of `cuxfilter` : ```bash # for CUDA 12.0 conda install -c rapidsai -c conda-forge -c nvidia \ - cuxfilter python=3.10 cuda-version=12.0 + cuxfilter python=3.11 cuda-version=12.0 # for CUDA 11.8 conda install -c rapidsai -c conda-forge -c nvidia \ - cuxfilter python=3.10 cuda-version=11.8 + cuxfilter python=3.11 cuda-version=11.8 ``` Note: cuxfilter is supported only on Linux, and with Python versions 3.8 and later. diff --git a/VERSION b/VERSION index 3c6c5e2b..4a2fe8aa 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -24.02.00 +24.04.00 diff --git a/ci/build_docs.sh b/ci/build_docs.sh index 0d9c2833..7683fb88 100755 --- a/ci/build_docs.sh +++ b/ci/build_docs.sh @@ -10,7 +10,7 @@ rapids-dependency-file-generator \ --file_key docs \ --matrix "cuda=${RAPIDS_CUDA_VERSION%.*};arch=$(arch);py=${RAPIDS_PY_VERSION}" | tee env.yaml -rapids-mamba-retry env create --force -f env.yaml -n docs +rapids-mamba-retry env create --yes -f env.yaml -n docs conda activate docs rapids-print-env @@ -23,7 +23,9 @@ rapids-mamba-retry install \ --channel "${PYTHON_CHANNEL}" \ cuxfilter -export RAPIDS_VERSION_NUMBER="24.02" +export RAPIDS_VERSION="$(rapids-version)" +export RAPIDS_VERSION_MAJOR_MINOR="$(rapids-version-major-minor)" +export RAPIDS_VERSION_NUMBER="$RAPIDS_VERSION_MAJOR_MINOR" export RAPIDS_DOCS_DIR="$(mktemp -d)" rapids-logger "Build Python docs" diff --git a/ci/build_wheel.sh b/ci/build_wheel.sh index be97d837..b8169511 100755 --- a/ci/build_wheel.sh +++ b/ci/build_wheel.sh @@ -47,4 +47,4 @@ cd "${package_dir}" python -m pip wheel . -w dist -vvv --no-deps --disable-pip-version-check -RAPIDS_PY_WHEEL_NAME="${package_name}_${RAPIDS_PY_CUDA_SUFFIX}" rapids-upload-wheels-to-s3 dist +RAPIDS_PY_WHEEL_NAME="${package_name}_${RAPIDS_PY_CUDA_SUFFIX}" RAPIDS_PY_WHEEL_PURE="1" rapids-upload-wheels-to-s3 dist diff --git a/ci/check_style.sh b/ci/check_style.sh index be3ac3f4..9bc26fe7 100755 --- a/ci/check_style.sh +++ b/ci/check_style.sh @@ -11,7 +11,7 @@ rapids-dependency-file-generator \ --file_key checks \ --matrix "cuda=${RAPIDS_CUDA_VERSION%.*};arch=$(arch);py=${RAPIDS_PY_VERSION}" | tee env.yaml -rapids-mamba-retry env create --force -f env.yaml -n checks +rapids-mamba-retry env create --yes -f env.yaml -n checks conda activate checks # Run pre-commit checks diff --git a/ci/release/update-version.sh b/ci/release/update-version.sh index e36b9370..f56a514c 100755 --- a/ci/release/update-version.sh +++ b/ci/release/update-version.sh @@ -33,9 +33,6 @@ function sed_runner() { sed -i.bak ''"$1"'' $2 && rm -f ${2}.bak } -# RTD update -sed_runner 's/version = .*/version = '"'${NEXT_SHORT_TAG}'"'/g' docs/source/conf.py -sed_runner 's/release = .*/release = '"'${NEXT_FULL_TAG}'"'/g' docs/source/conf.py # docs update sed_runner "/cuxfilter=[0-9]\{2\}.[0-9]\{2\}/ s/=[0-9]\{2\}.[0-9]\{2\}/=${NEXT_SHORT_TAG}/g" docs/source/user_guide/installation.rst @@ -53,10 +50,10 @@ DEPENDENCIES=( ) for DEP in "${DEPENDENCIES[@]}"; do for FILE in dependencies.yaml conda/environments/*.yaml ci/utils/external_dependencies.yaml; do - sed_runner "/-.* ${DEP}==/ s/==.*/==${NEXT_SHORT_TAG_PEP440}.*/g" ${FILE} + sed_runner "/-.* ${DEP}\(-cu[[:digit:]]\{2\}\)\{0,1\}==/ s/==.*/==${NEXT_SHORT_TAG_PEP440}.*/g" "${FILE}" done for FILE in python/pyproject.toml; do - sed_runner "/\"${DEP}==/ s/==.*\"/==${NEXT_SHORT_TAG_PEP440}.*\"/g" ${FILE} + sed_runner "/\"${DEP}\(-cu[[:digit:]]\{2\}\)\{0,1\}==/ s/==.*\"/==${NEXT_SHORT_TAG_PEP440}.*\"/g" "${FILE}" done done @@ -69,6 +66,3 @@ sed_runner "/cuxfilter=[0-9]\{2\}.[0-9]\{2\}/ s/=[0-9]\{2\}.[0-9]\{2\}/=${NEXT_S for FILE in .github/workflows/*.yaml; do sed_runner "/shared-workflows/ s/@.*/@branch-${NEXT_SHORT_TAG}/g" ${FILE}; done - -sed_runner "s/RAPIDS_VERSION_NUMBER=\".*/RAPIDS_VERSION_NUMBER=\"${NEXT_SHORT_TAG}\"/g" ci/build_docs.sh -sed_runner "s/RAPIDS_VERSION=.*/RAPIDS_VERSION=${NEXT_SHORT_TAG}.*/g" ci/test_external.sh diff --git a/ci/test_external.sh b/ci/test_external.sh index 87b68dc3..613b7d1f 100755 --- a/ci/test_external.sh +++ b/ci/test_external.sh @@ -80,7 +80,10 @@ trap "EXITCODE=1" ERR set +e rapids-logger "running all gathered tests" -DATASHADER_TEST_GPU=1 pytest --numprocesses=8 $FILES +DATASHADER_TEST_GPU=1 pytest \ + --numprocesses=8 \ + --dist=worksteal \ + $FILES if [[ "$PROJECT" = "all" ]] || [[ "$PROJECT" = "datashader" ]]; then # run test_quadmesh.py separately as dask.array tests fail with numprocesses diff --git a/ci/test_notebooks.sh b/ci/test_notebooks.sh index d27f41ec..01ef8474 100755 --- a/ci/test_notebooks.sh +++ b/ci/test_notebooks.sh @@ -11,7 +11,7 @@ rapids-dependency-file-generator \ --file_key test_notebooks \ --matrix "cuda=${RAPIDS_CUDA_VERSION%.*};arch=$(arch);py=${RAPIDS_PY_VERSION}" | tee env.yaml -rapids-mamba-retry env create --force -f env.yaml -n test +rapids-mamba-retry env create --yes -f env.yaml -n test # Temporarily allow unbound variables for conda activation. set +u diff --git a/ci/test_python.sh b/ci/test_python.sh index af505feb..617ff327 100755 --- a/ci/test_python.sh +++ b/ci/test_python.sh @@ -11,7 +11,7 @@ rapids-dependency-file-generator \ --file_key test_python \ --matrix "cuda=${RAPIDS_CUDA_VERSION%.*};arch=$(arch);py=${RAPIDS_PY_VERSION}" | tee env.yaml -rapids-mamba-retry env create --force -f env.yaml -n test +rapids-mamba-retry env create --yes -f env.yaml -n test # Temporarily allow unbound variables for conda activation. set +u @@ -44,6 +44,7 @@ pytest \ --cache-clear \ --junitxml="${RAPIDS_TESTS_DIR}/junit-cuxfilter.xml" \ --numprocesses=8 \ + --dist=worksteal \ --cov-config=.coveragerc \ --cov=cuxfilter \ --cov-report=xml:"${RAPIDS_COVERAGE_DIR}/cuxfilter-coverage.xml" \ diff --git a/ci/test_wheel.sh b/ci/test_wheel.sh index 5087d221..c1253fe9 100755 --- a/ci/test_wheel.sh +++ b/ci/test_wheel.sh @@ -4,7 +4,7 @@ set -eou pipefail RAPIDS_PY_CUDA_SUFFIX="$(rapids-wheel-ctk-name-gen ${RAPIDS_CUDA_VERSION})" -RAPIDS_PY_WHEEL_NAME="cuxfilter_${RAPIDS_PY_CUDA_SUFFIX}" rapids-download-wheels-from-s3 ./dist +RAPIDS_PY_WHEEL_NAME="cuxfilter_${RAPIDS_PY_CUDA_SUFFIX}" RAPIDS_PY_WHEEL_PURE="1" rapids-download-wheels-from-s3 ./dist # echo to expand wildcard before adding `[extra]` requires for pip python -m pip install $(echo ./dist/cuxfilter*.whl)[test] diff --git a/ci/utils/external_dependencies.yaml b/ci/utils/external_dependencies.yaml index 265a9144..b71ba541 100644 --- a/ci/utils/external_dependencies.yaml +++ b/ci/utils/external_dependencies.yaml @@ -4,11 +4,11 @@ channels: - conda-forge - nvidia dependencies: - - cudf==24.2.* - - dask-cudf==24.2.* - - cuxfilter==24.2.* + - cudf==24.4.* + - dask-cudf==24.4.* + - cuxfilter==24.4.* - cuda-version=12.0 - - python>=3.9,<3.11 + - python>=3.9,<3.12 - xarray-spatial - pycaret - graphistry diff --git a/conda/environments/all_cuda-118_arch-x86_64.yaml b/conda/environments/all_cuda-118_arch-x86_64.yaml index 4e2cc92b..56748b00 100644 --- a/conda/environments/all_cuda-118_arch-x86_64.yaml +++ b/conda/environments/all_cuda-118_arch-x86_64.yaml @@ -9,12 +9,12 @@ dependencies: - bokeh>=3.1 - cuda-version=11.8 - cudatoolkit -- cudf==24.2.* -- cugraph==24.2.* +- cudf==24.4.* +- cugraph==24.4.* - cupy>=12.0.0 -- cuspatial==24.2.* -- dask-cuda==24.2.* -- dask-cudf==24.2.* +- cuspatial==24.4.* +- dask-cuda==24.4.* +- dask-cudf==24.4.* - datashader>=0.15 - geopandas>=0.11.0 - holoviews>=1.16.0 @@ -24,10 +24,10 @@ dependencies: - jupyter_sphinx - libwebp - nbsphinx -- nodejs>=14 +- nodejs>=18 - notebook>=0.5.0 - numba>=0.57 -- numpy>=1.21 +- numpy>=1.23,<2.0a0 - numpydoc - packaging - pandoc<=2.0.0 @@ -38,7 +38,7 @@ dependencies: - pytest - pytest-cov - pytest-xdist -- python>=3.9,<3.11 +- python>=3.9,<3.12 - recommonmark - sphinx-markdown-tables - sphinx>=7.2.5 diff --git a/conda/environments/all_cuda-120_arch-x86_64.yaml b/conda/environments/all_cuda-122_arch-x86_64.yaml similarity index 77% rename from conda/environments/all_cuda-120_arch-x86_64.yaml rename to conda/environments/all_cuda-122_arch-x86_64.yaml index c78cc8c8..25f16076 100644 --- a/conda/environments/all_cuda-120_arch-x86_64.yaml +++ b/conda/environments/all_cuda-122_arch-x86_64.yaml @@ -7,13 +7,13 @@ channels: - nvidia dependencies: - bokeh>=3.1 -- cuda-version=12.0 -- cudf==24.2.* -- cugraph==24.2.* +- cuda-version=12.2 +- cudf==24.4.* +- cugraph==24.4.* - cupy>=12.0.0 -- cuspatial==24.2.* -- dask-cuda==24.2.* -- dask-cudf==24.2.* +- cuspatial==24.4.* +- dask-cuda==24.4.* +- dask-cudf==24.4.* - datashader>=0.15 - geopandas>=0.11.0 - holoviews>=1.16.0 @@ -23,10 +23,10 @@ dependencies: - jupyter_sphinx - libwebp - nbsphinx -- nodejs>=14 +- nodejs>=18 - notebook>=0.5.0 - numba>=0.57 -- numpy>=1.21 +- numpy>=1.23,<2.0a0 - numpydoc - packaging - pandoc<=2.0.0 @@ -37,10 +37,10 @@ dependencies: - pytest - pytest-cov - pytest-xdist -- python>=3.9,<3.11 +- python>=3.9,<3.12 - recommonmark - sphinx-markdown-tables - sphinx>=7.2.5 - sphinx_rtd_theme - sphinxcontrib-websupport -name: all_cuda-120_arch-x86_64 +name: all_cuda-122_arch-x86_64 diff --git a/conda/recipes/cuxfilter/meta.yaml b/conda/recipes/cuxfilter/meta.yaml index 5e3f3a93..d0ee3ae5 100644 --- a/conda/recipes/cuxfilter/meta.yaml +++ b/conda/recipes/cuxfilter/meta.yaml @@ -36,7 +36,7 @@ requirements: - libwebp - nodejs >=14 - numba >=0.57 - - numpy >=1.21 + - numpy >=1.23,<2.0a0 - packaging - panel >=1.0 - pyppeteer >=0.2.6 diff --git a/dependencies.yaml b/dependencies.yaml index ed759b6f..15a087a6 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -3,7 +3,7 @@ files: all: output: conda matrix: - cuda: ["11.8", "12.0"] + cuda: ["11.8", "12.2"] arch: [x86_64] includes: - build_wheels @@ -97,6 +97,10 @@ dependencies: cuda: "12.0" packages: - cuda-version=12.0 + - matrix: + cuda: "12.2" + packages: + - cuda-version=12.2 cuda: specific: - output_types: conda @@ -137,8 +141,8 @@ dependencies: - notebook>=0.5.0 - output_types: [conda] packages: - - cugraph==24.2.* - - dask-cuda==24.2.* + - cugraph==24.4.* + - dask-cuda==24.4.* py_version: specific: - output_types: conda @@ -151,29 +155,33 @@ dependencies: py: "3.10" packages: - python=3.10 + - matrix: + py: "3.11" + packages: + - python=3.11 - matrix: packages: - - python>=3.9,<3.11 + - python>=3.9,<3.12 run: common: - output_types: [conda, requirements, pyproject] packages: - bokeh>=3.1 - - cudf==24.2.* - - cuspatial==24.2.* - - dask-cudf==24.2.* + - cudf==24.4.* + - cuspatial==24.4.* + - dask-cudf==24.4.* - datashader>=0.15 - geopandas>=0.11.0 - holoviews>=1.16.0 - jupyter-server-proxy - numba>=0.57 - - numpy>=1.21 + - numpy>=1.23,<2.0a0 - packaging - panel>=1.0 - output_types: conda packages: - cupy>=12.0.0 - - nodejs>=14 + - nodejs>=18 - libwebp - output_types: [requirements, pyproject] packages: diff --git a/docs/source/conf.py b/docs/source/conf.py index ddda56e0..086f2927 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,5 +1,9 @@ # Copyright (c) 2019-2023, NVIDIA CORPORATION. +from packaging.version import Version + +import cuxfilter + # -- Project information ----------------------------------------------------- project = "cuxfilter" copyright = "2018-2023, NVIDIA Corporation" @@ -9,10 +13,11 @@ # |version| and |release|, also used in various other places throughout the # built documents. # +CUXFILTER_VERSION = Version(cuxfilter.__version__) # The short X.Y version. -version = '24.02' +version = f"{CUXFILTER_VERSION.major:02}.{CUXFILTER_VERSION.minor:02}" # The full version, including alpha/beta/rc tags -release = '24.02.00' +release = f"{CUXFILTER_VERSION.major:02}.{CUXFILTER_VERSION.minor:02}.{CUXFILTER_VERSION.micro:02}" nbsphinx_allow_errors = True diff --git a/docs/source/user_guide/installation.rst b/docs/source/user_guide/installation.rst index 8e8eafef..2261f8a6 100644 --- a/docs/source/user_guide/installation.rst +++ b/docs/source/user_guide/installation.rst @@ -9,11 +9,11 @@ For the most customized way of installing RAPIDS and cuxfilter, visit the select # for CUDA 12.0 conda install -c rapidsai -c conda-forge -c nvidia \ - cuxfilter=24.02 python=3.10 cuda-version=12.0 + cuxfilter=24.04 python=3.10 cuda-version=12.0 # for CUDA 11.8 conda install -c rapidsai -c conda-forge -c nvidia \ - cuxfilter=24.02 python=3.10 cuda-version=11.8 + cuxfilter=24.04 python=3.10 cuda-version=11.8 PyPI ---- diff --git a/notebooks/README.md b/notebooks/README.md index 9c04137f..1ce2f4fb 100644 --- a/notebooks/README.md +++ b/notebooks/README.md @@ -39,11 +39,11 @@ conda install ipykernel # for stable rapids version conda install -c rapidsai -c numba -c conda-forge -c nvidia \ - cuxfilter=23.02 python=3.10 cudatoolkit=11.8 + cuxfilter=23.02 python=3.11 cudatoolkit=11.8 # for nightly rapids version conda install -c rapidsai-nightly -c numba -c conda-forge -c nvidia \ - cuxfilter python=3.10 cudatoolkit=11.8 + cuxfilter python=3.11 cudatoolkit=11.8 ``` > Above are sample install snippets for cuxfilter, see the [Get RAPIDS version picker](https://rapids.ai/start.html) for installing the latest `cuxfilter` version. diff --git a/python/cuxfilter/assets/geojson_mapper.py b/python/cuxfilter/assets/geojson_mapper.py index 5fa2e4d5..48af4e53 100644 --- a/python/cuxfilter/assets/geojson_mapper.py +++ b/python/cuxfilter/assets/geojson_mapper.py @@ -1,6 +1,7 @@ from urllib.request import urlopen import geopandas as gpd import pandas as pd +from io import StringIO def geo_json_mapper( @@ -16,7 +17,7 @@ def geo_json_mapper( temp_gpd_df = gpd.read_file(data).to_crs(epsg=projection) - df = pd.read_json(temp_gpd_df.to_json()) + df = pd.read_json(StringIO(temp_gpd_df.to_json())) x_range = ( temp_gpd_df.geometry.bounds.minx.min(), diff --git a/python/cuxfilter/charts/bokeh/plots/bar.py b/python/cuxfilter/charts/bokeh/plots/bar.py index 79158731..3c5ea43c 100644 --- a/python/cuxfilter/charts/bokeh/plots/bar.py +++ b/python/cuxfilter/charts/bokeh/plots/bar.py @@ -111,7 +111,7 @@ def calculate_source(self, data=None): Output: cudf.DataFrame """ - data = data or self.source + data = self.source if data is None else data return calc_groupby(self, data) def reload_chart(self, data): diff --git a/python/cuxfilter/charts/bokeh/plots/histogram.py b/python/cuxfilter/charts/bokeh/plots/histogram.py index bba77a8b..c6d6481f 100644 --- a/python/cuxfilter/charts/bokeh/plots/histogram.py +++ b/python/cuxfilter/charts/bokeh/plots/histogram.py @@ -112,7 +112,7 @@ def calculate_source(self, data=None): Output: cudf.DataFrame """ - data = data or self.source + data = self.source if data is None else data return calc_value_counts( data[self.x], self.stride, diff --git a/python/cuxfilter/charts/core/aggregate/core_aggregate.py b/python/cuxfilter/charts/core/aggregate/core_aggregate.py index f660e57f..b2a0ba09 100644 --- a/python/cuxfilter/charts/core/aggregate/core_aggregate.py +++ b/python/cuxfilter/charts/core/aggregate/core_aggregate.py @@ -187,12 +187,12 @@ def reset_callback(resetting): def get_box_select_callback(self, dashboard_cls): def cb(bounds, x_selection, y_selection): self.box_selected_range, self.selected_indices = None, None - if type(x_selection) == tuple: + if isinstance(x_selection, tuple): self.box_selected_range = { self.x + "_min": x_selection[0], self.x + "_max": x_selection[1], } - elif type(x_selection) == list: + elif isinstance(x_selection, list): self.selected_indices = ( dashboard_cls._cuxfilter_df.data[self.x] .isin(x_selection) diff --git a/python/cuxfilter/charts/core/non_aggregate/utils.py b/python/cuxfilter/charts/core/non_aggregate/utils.py index 5b084ebe..ca090476 100644 --- a/python/cuxfilter/charts/core/non_aggregate/utils.py +++ b/python/cuxfilter/charts/core/non_aggregate/utils.py @@ -10,4 +10,4 @@ def point_in_polygon(df, x, y, polygons): polygons = cuspatial.GeoSeries( gpd.GeoSeries(Polygon(polygons)), index=["selection"] ) - return cuspatial.point_in_polygon(points, polygons) + return cuspatial.point_in_polygon(points, polygons).selection diff --git a/python/cuxfilter/charts/datashader/custom_extensions/graph_assets.py b/python/cuxfilter/charts/datashader/custom_extensions/graph_assets.py index 5338bc20..f9c6ad67 100644 --- a/python/cuxfilter/charts/datashader/custom_extensions/graph_assets.py +++ b/python/cuxfilter/charts/datashader/custom_extensions/graph_assets.py @@ -81,10 +81,9 @@ def bundle_edges(edges, src="src", dst="dst"): # Determine each edge's index relative to its bundle edges = edges.sort_values(by="bid").reset_index(drop=True) - edges["_index"] = ( - cudf.core.index.RangeIndex(0, len(edges)) - edges["start"] - ).astype("int32") - + edges["_index"] = (cudf.RangeIndex(0, len(edges)) - edges["start"]).astype( + "int32" + ) # Re-sort the edgelist by edge id and cleanup edges = edges.sort_values("eid").reset_index(drop=True) edges = edges.rename(columns={"eid": "id"}, copy=False) diff --git a/python/cuxfilter/charts/datashader/custom_extensions/holoviews_datashader.py b/python/cuxfilter/charts/datashader/custom_extensions/holoviews_datashader.py index 92c26695..548bf498 100644 --- a/python/cuxfilter/charts/datashader/custom_extensions/holoviews_datashader.py +++ b/python/cuxfilter/charts/datashader/custom_extensions/holoviews_datashader.py @@ -221,6 +221,8 @@ class InteractiveDatashaderPoints(InteractiveDatashader): ) max_px = param.Integer(10) clims = param.Tuple(default=(None, None)) + xaxis = param.Boolean(default=False, doc="display the xaxis with labels") + yaxis = param.Boolean(default=False, doc="display the yaxis with labels") def __init__(self, **params): super(InteractiveDatashaderPoints, self).__init__(**params) @@ -229,7 +231,7 @@ def __init__(self, **params): def _compute_clims(self): if not isinstance( self.source_df[self.aggregate_col].dtype, - cudf.core.dtypes.CategoricalDtype, + cudf.CategoricalDtype, ): self.clims = get_min_max(self.source_df, self.aggregate_col) @@ -238,7 +240,7 @@ def _compute_datashader_assets(self): self.cmap = {"cmap": self.color_palette} if isinstance( self.source_df[self.aggregate_col].dtype, - cudf.core.dtypes.CategoricalDtype, + cudf.CategoricalDtype, ): self.cmap = { "color_key": { @@ -306,6 +308,15 @@ def get_chart(self, streams=[]): return dmap def view(self): + parameters = dict( + responsive=True, + tools=self.tools, + active_tools=["wheel_zoom", "pan"], + ) + if self.xaxis is False: + parameters["xaxis"] = None + if self.yaxis is False: + parameters["yaxis"] = None dmap = dynspread( self.get_chart( streams=[ @@ -317,13 +328,7 @@ def view(self): threshold=self.spread_threshold, shape=self.point_shape, max_px=self.max_px, - ).opts( - xaxis=None, - yaxis=None, - responsive=True, - tools=self.tools, - active_tools=["wheel_zoom", "pan"], - ) + ).opts(**parameters) if self.unselected_alpha > 0: dmap *= self.get_base_chart() @@ -548,6 +553,8 @@ class InteractiveDatashaderGraph(InteractiveDatashaderBase): class_=CustomInspectTool, doc="tool to select whether to display edges or not", ) + xaxis = param.Boolean(default=False, doc="display the xaxis with labels") + yaxis = param.Boolean(default=False, doc="display the yaxis with labels") @property def df_type(self): @@ -604,6 +611,19 @@ def set_tools(plot, element): plot.state.add_tools(self.inspect_neighbors) plot.state.add_tools(self.display_edges) + parameters = dict( + responsive=True, + default_tools=[], + active_tools=["wheel_zoom", "pan"], + tools=self.tools, + hooks=[set_tools], + ) + + if self.xaxis is False: + parameters["xaxis"] = None + if self.yaxis is False: + parameters["yaxis"] = None + dmap_nodes = dynspread( self.nodes_chart.get_chart( streams=[ @@ -615,15 +635,7 @@ def set_tools(plot, element): threshold=self.node_spread_threshold, shape=self.node_point_shape, max_px=self.node_max_px, - ).opts( - xaxis=None, - yaxis=None, - responsive=True, - default_tools=[], - active_tools=["wheel_zoom", "pan"], - tools=self.tools, - hooks=[set_tools], - ) + ).opts(**parameters) dmap_edges = dynspread( self.edges_chart.get_chart().opts(default_tools=[]) diff --git a/python/cuxfilter/charts/datashader/datashader.py b/python/cuxfilter/charts/datashader/datashader.py index b340a94e..0ade59fb 100644 --- a/python/cuxfilter/charts/datashader/datashader.py +++ b/python/cuxfilter/charts/datashader/datashader.py @@ -21,6 +21,8 @@ def scatter( legend=True, legend_position="top_right", unselected_alpha=0.2, + xaxis=False, + yaxis=False, ): """ Parameters @@ -93,6 +95,12 @@ def scatter( if True, displays unselected data in the same color_palette but transparent(alpha=0.2) + xaxis: bool, default False + if True, displays the xaxis with labels + + yaxis: bool, default False + if True, displays the yaxis with labels + Returns ------- A cudashader scatter plot of type: @@ -118,6 +126,8 @@ def scatter( legend=legend, legend_position=legend_position, unselected_alpha=unselected_alpha, + xaxis=xaxis, + yaxis=yaxis, ) plot.chart_type = "scatter" @@ -153,6 +163,8 @@ def graph( legend=True, legend_position="top_right", unselected_alpha=0.2, + xaxis=False, + yaxis=False, ): """ Parameters @@ -258,6 +270,12 @@ def graph( if True, displays unselected data in the same color_palette but transparent(alpha=0.2) (nodes only) + xaxis: bool, default False + if True, displays the xaxis with labels + + yaxis: bool, default False + if True, displays the yaxis with labels + Returns ------- A cudashader graph plot of type: @@ -292,6 +310,8 @@ def graph( legend=legend, legend_position=legend_position, unselected_alpha=unselected_alpha, + xaxis=xaxis, + yaxis=yaxis, ) plot.chart_type = "graph" @@ -314,6 +334,8 @@ def heatmap( legend=True, legend_position="top_right", unselected_alpha=0.2, + xaxis=True, + yaxis=True, ): """ Heatmap using default datashader.scatter plot with slight modifications. @@ -380,6 +402,12 @@ def heatmap( if True, displays unselected data in the same color_palette but transparent(alpha=0.2) + xaxis: bool, default True + if True, displays the xaxis with labels + + yaxis: bool, default True + if True, displays the yaxis with labels + Returns ------- A cudashader heatmap (scatter object) of type: @@ -405,6 +433,8 @@ def heatmap( legend=legend, legend_position=legend_position, unselected_alpha=unselected_alpha, + xaxis=xaxis, + yaxis=yaxis, ) plot.chart_type = "heatmap" return plot diff --git a/python/cuxfilter/charts/datashader/plots.py b/python/cuxfilter/charts/datashader/plots.py index 8176dce4..8093a780 100644 --- a/python/cuxfilter/charts/datashader/plots.py +++ b/python/cuxfilter/charts/datashader/plots.py @@ -93,6 +93,8 @@ def generate_chart(self): max_px=self.point_size, unselected_alpha=self.unselected_alpha, title=self.title, + xaxis=self.library_specific_params["xaxis"], + yaxis=self.library_specific_params["yaxis"], ) def reload_chart(self, data=None): @@ -231,6 +233,8 @@ def cb(attr, old, new): display_edges=self.display_edges, unselected_alpha=self.unselected_alpha, title=self.title, + xaxis=self.library_specific_params["xaxis"], + yaxis=self.library_specific_params["yaxis"], ) def reload_chart(self, data, edges=None): diff --git a/python/cuxfilter/charts/deckgl/bindings/panel_deck.py b/python/cuxfilter/charts/deckgl/bindings/panel_deck.py index 7623a507..c6502e85 100644 --- a/python/cuxfilter/charts/deckgl/bindings/panel_deck.py +++ b/python/cuxfilter/charts/deckgl/bindings/panel_deck.py @@ -45,7 +45,7 @@ class PanelDeck(param.Parameterized): @property def valid_indices(self): - return self.indices.intersection(self.data.index) + return list(self.indices.intersection(self.data.index)) def get_tooltip_html(self): """ @@ -110,7 +110,8 @@ def click_event(self): temp_colors = self.colors.copy() if len(self.indices) > 0: temp_colors.loc[ - set(self.data.index) - self.indices, self.colors.columns + list(set(self.data.index) - self.indices), + self.colors.columns, ] = self.default_color self.data[self.colors.columns] = temp_colors self._update_layer_data(self.data) diff --git a/python/cuxfilter/charts/panel_widgets/plots.py b/python/cuxfilter/charts/panel_widgets/plots.py index aadefb68..10c675de 100644 --- a/python/cuxfilter/charts/panel_widgets/plots.py +++ b/python/cuxfilter/charts/panel_widgets/plots.py @@ -1,3 +1,4 @@ +import datetime from ..core import BaseWidget from ..core.aggregate import BaseNumberChart from ..constants import ( @@ -160,7 +161,10 @@ def compute_query_dict(self, query_str_dict, query_local_variables_dict): reference to dashboard.__cls__.query_dict """ if self.chart.value != (self.chart.start, self.chart.end): - min_temp, max_temp = self.chart.value + min_temp, max_temp = ( + datetime.datetime.fromordinal(x.toordinal()) + for x in self.chart.value + ) query = f"@{self.x}_min<={self.x}<=@{self.x}_max" query_str_dict[self.name] = query query_local_variables_dict[self.x + "_min"] = min_temp @@ -328,9 +332,7 @@ def initiate_chart(self, dashboard_cls): self.min_value, self.max_value = get_min_max( dashboard_cls._cuxfilter_df.data, self.x ) - self.source = dashboard_cls._cuxfilter_df.data[self.x].reset_index( - drop=True - ) + self.source = dashboard_cls._cuxfilter_df.data[self.x] self.calc_list_of_values(dashboard_cls._cuxfilter_df.data) self.generate_widget() self.add_events(dashboard_cls) @@ -396,17 +398,20 @@ def compute_query_dict(self, query_str_dict, query_local_variables_dict): if len(self.chart.value) == 0: query_str_dict.pop(self.name, None) else: - df_module = ( - cudf if isinstance(self.source, cudf.Series) else dask_cudf - ) - if self.source.dtype == "object": - query_str_dict[self.name] = df_module.DataFrame( - self.source.str.contains("|".join(self.chart.value)) + def filter_source(s: cudf.Series, v: list): + if s.dtype == "object": + return s.str.contains("|".join(v)) + else: + return s.isin(v) + + if isinstance(self.source, dask_cudf.Series): + query_str_dict[self.name] = self.source.map_partitions( + filter_source, self.chart.value ) - else: - query_str_dict[self.name] = df_module.DataFrame( - self.source.isin(self.chart.value) + elif isinstance(self.source, cudf.Series): + query_str_dict[self.name] = filter_source( + self.source, self.chart.value ) def apply_theme(self, theme): diff --git a/python/cuxfilter/dashboard.py b/python/cuxfilter/dashboard.py index a6d265b4..de52c223 100644 --- a/python/cuxfilter/dashboard.py +++ b/python/cuxfilter/dashboard.py @@ -119,7 +119,7 @@ def queried_indices(self): """ Read-only propery queried_indices returns a merged index of all queried index columns present in self._query_str_dict - as a cudf.Series. + as a `cudf.Series` or `dask_cudf.Series`. Returns None if no index columns are present. @@ -132,13 +132,20 @@ def queried_indices(self): else dask_cudf ) selected_indices = { - key: value + key: value.reset_index(drop=True) for (key, value) in self._query_str_dict.items() - if type(value) in [cudf.DataFrame, dask_cudf.DataFrame] + if type(value) + in [ + cudf.DataFrame, + dask_cudf.DataFrame, + cudf.Series, + dask_cudf.Series, + ] } if len(selected_indices) > 0: result = ( df_module.concat(list(selected_indices.values()), axis=1) + .set_index(self._cuxfilter_df.data.index) .fillna(False) .all(axis=1) ) diff --git a/python/cuxfilter/tests/charts/deckgl/test_deckgl.py b/python/cuxfilter/tests/charts/deckgl/test_deckgl.py index ec869925..a577d619 100644 --- a/python/cuxfilter/tests/charts/deckgl/test_deckgl.py +++ b/python/cuxfilter/tests/charts/deckgl/test_deckgl.py @@ -81,6 +81,7 @@ def test_init(self, cux_df): ) assert choropleth3d_chart.chart.indices == set() + assert choropleth3d_chart.chart.valid_indices == list() assert choropleth3d_chart.chart.multi_select is False diff --git a/python/pyproject.toml b/python/pyproject.toml index 0d6533d7..6a129423 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -19,16 +19,16 @@ license = { text = "Apache 2.0" } requires-python = ">=3.9" dependencies = [ "bokeh>=3.1", - "cudf==24.2.*", + "cudf==24.4.*", "cupy-cuda11x>=12.0.0", - "cuspatial==24.2.*", - "dask-cudf==24.2.*", + "cuspatial==24.4.*", + "dask-cudf==24.4.*", "datashader>=0.15", "geopandas>=0.11.0", "holoviews>=1.16.0", "jupyter-server-proxy", "numba>=0.57", - "numpy>=1.21", + "numpy>=1.23,<2.0a0", "packaging", "panel>=1.0", ] # This list was generated by `rapids-dependency-file-generator`. To make changes, edit ../dependencies.yaml and run `rapids-dependency-file-generator`. @@ -40,6 +40,7 @@ classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", ] [project.optional-dependencies]