polars2svg 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- polars2svg-0.1.0/.github/dependabot.yml +14 -0
- polars2svg-0.1.0/.github/workflows/ci.yml +96 -0
- polars2svg-0.1.0/.github/workflows/docs.yml +50 -0
- polars2svg-0.1.0/.github/workflows/release.yml +63 -0
- polars2svg-0.1.0/.gitignore +222 -0
- polars2svg-0.1.0/CHANGELOG.md +130 -0
- polars2svg-0.1.0/CITATION.cff +163 -0
- polars2svg-0.1.0/CONTRIBUTING.md +159 -0
- polars2svg-0.1.0/LICENSE +201 -0
- polars2svg-0.1.0/NOTICE +24 -0
- polars2svg-0.1.0/PKG-INFO +311 -0
- polars2svg-0.1.0/README.md +230 -0
- polars2svg-0.1.0/SECURITY.md +77 -0
- polars2svg-0.1.0/docs/components/chordp.md +39 -0
- polars2svg-0.1.0/docs/components/histop.md +37 -0
- polars2svg-0.1.0/docs/components/index.md +55 -0
- polars2svg-0.1.0/docs/components/linkp.md +48 -0
- polars2svg-0.1.0/docs/components/piep.md +29 -0
- polars2svg-0.1.0/docs/components/smallp.md +42 -0
- polars2svg-0.1.0/docs/components/spreadlinesp.md +30 -0
- polars2svg-0.1.0/docs/components/timep.md +44 -0
- polars2svg-0.1.0/docs/components/xyp.md +45 -0
- polars2svg-0.1.0/docs/examples/chordp_flows.svg +1 -0
- polars2svg-0.1.0/docs/examples/histop_bars.svg +1 -0
- polars2svg-0.1.0/docs/examples/linkp_network.svg +1 -0
- polars2svg-0.1.0/docs/examples/piep_donut.svg +1 -0
- polars2svg-0.1.0/docs/examples/smallp_facets.svg +33 -0
- polars2svg-0.1.0/docs/examples/spreadlinesp_ego.svg +1 -0
- polars2svg-0.1.0/docs/examples/timep_linear.svg +1 -0
- polars2svg-0.1.0/docs/examples/timep_periodic.svg +1 -0
- polars2svg-0.1.0/docs/examples/xyp_scatter.svg +9 -0
- polars2svg-0.1.0/docs/gen_examples.py +181 -0
- polars2svg-0.1.0/docs/getting-started.md +92 -0
- polars2svg-0.1.0/docs/guides/count-color.md +88 -0
- polars2svg-0.1.0/docs/guides/interactivity.md +64 -0
- polars2svg-0.1.0/docs/guides/t-fields.md +64 -0
- polars2svg-0.1.0/docs/index.md +57 -0
- polars2svg-0.1.0/mkdocs.yml +60 -0
- polars2svg-0.1.0/polars2svg/__init__.py +36 -0
- polars2svg-0.1.0/polars2svg/chordp.py +2239 -0
- polars2svg-0.1.0/polars2svg/circle_packer.py +313 -0
- polars2svg-0.1.0/polars2svg/config/udist_scatterplots_via_sectors_tile_opt.parquet +0 -0
- polars2svg-0.1.0/polars2svg/convey_proximity_layout.py +249 -0
- polars2svg-0.1.0/polars2svg/exceptions.py +8 -0
- polars2svg-0.1.0/polars2svg/export.py +86 -0
- polars2svg-0.1.0/polars2svg/fonts/NotoSans-Regular-subset.ttf +0 -0
- polars2svg-0.1.0/polars2svg/fonts/OFL.txt +93 -0
- polars2svg-0.1.0/polars2svg/histop.py +1209 -0
- polars2svg-0.1.0/polars2svg/interactive_controller.py +3098 -0
- polars2svg-0.1.0/polars2svg/laguerre_voronoi.py +290 -0
- polars2svg-0.1.0/polars2svg/layout_protocol.py +49 -0
- polars2svg-0.1.0/polars2svg/linkp.py +1843 -0
- polars2svg-0.1.0/polars2svg/mds_at_scale.py +267 -0
- polars2svg-0.1.0/polars2svg/p2s_colors_mixin.py +336 -0
- polars2svg-0.1.0/polars2svg/p2s_displaylist.py +569 -0
- polars2svg-0.1.0/polars2svg/p2s_geometry_mixin.py +253 -0
- polars2svg-0.1.0/polars2svg/p2s_glyph_atlas.py +133 -0
- polars2svg-0.1.0/polars2svg/p2s_graph_mixin.py +1462 -0
- polars2svg-0.1.0/polars2svg/p2s_interactive_mixin.py +94 -0
- polars2svg-0.1.0/polars2svg/p2s_legend_mixin.py +377 -0
- polars2svg-0.1.0/polars2svg/p2s_polars_mixin.py +86 -0
- polars2svg-0.1.0/polars2svg/p2s_render_mixin.py +362 -0
- polars2svg-0.1.0/polars2svg/p2s_text_mixin.py +170 -0
- polars2svg-0.1.0/polars2svg/p2s_time_mixin.py +258 -0
- polars2svg-0.1.0/polars2svg/p2s_webgpu_runtime.py +402 -0
- polars2svg-0.1.0/polars2svg/piep.py +1195 -0
- polars2svg-0.1.0/polars2svg/polars2svg.py +1950 -0
- polars2svg-0.1.0/polars2svg/polars_force_directed_layout.py +146 -0
- polars2svg-0.1.0/polars2svg/py.typed +0 -0
- polars2svg-0.1.0/polars2svg/smallp.py +517 -0
- polars2svg-0.1.0/polars2svg/spreadlinepi.py +385 -0
- polars2svg-0.1.0/polars2svg/spreadlinesp.py +1757 -0
- polars2svg-0.1.0/polars2svg/stack_control.py +250 -0
- polars2svg-0.1.0/polars2svg/tfdp_layout.py +417 -0
- polars2svg-0.1.0/polars2svg/timep.py +1459 -0
- polars2svg-0.1.0/polars2svg/udist_scatterplots_via_sectors_tile_opt.py +585 -0
- polars2svg-0.1.0/polars2svg/xyp.py +3517 -0
- polars2svg-0.1.0/pyproject.toml +194 -0
- polars2svg-0.1.0/tests/golden/basic_scatter.svg +9 -0
- polars2svg-0.1.0/tests/golden/chordp_count_weight.svg +1 -0
- polars2svg-0.1.0/tests/golden/chordp_default.svg +1 -0
- polars2svg-0.1.0/tests/golden/chordp_draw_labels_radial.svg +1 -0
- polars2svg-0.1.0/tests/golden/chordp_link_color_src.svg +1 -0
- polars2svg-0.1.0/tests/golden/chordp_link_color_vary.svg +1 -0
- polars2svg-0.1.0/tests/golden/chordp_link_shape_bundled.svg +1 -0
- polars2svg-0.1.0/tests/golden/chordp_node_color_by_name.svg +1 -0
- polars2svg-0.1.0/tests/golden/chordp_node_color_hex.svg +1 -0
- polars2svg-0.1.0/tests/golden/chordp_node_selection.svg +1 -0
- polars2svg-0.1.0/tests/golden/chordp_node_size_vary.svg +1 -0
- polars2svg-0.1.0/tests/golden/color_categorical.svg +9 -0
- polars2svg-0.1.0/tests/golden/color_continuous.svg +9 -0
- polars2svg-0.1.0/tests/golden/distributions.svg +9 -0
- polars2svg-0.1.0/tests/golden/histop_ascending_order.svg +1 -0
- polars2svg-0.1.0/tests/golden/histop_basic_barchart.svg +1 -0
- polars2svg-0.1.0/tests/golden/histop_color_categorical.svg +1 -0
- polars2svg-0.1.0/tests/golden/histop_color_crow_magnitude.svg +1 -0
- polars2svg-0.1.0/tests/golden/histop_color_crow_stretched.svg +1 -0
- polars2svg-0.1.0/tests/golden/histop_color_numeric.svg +1 -0
- polars2svg-0.1.0/tests/golden/histop_count_numeric_field.svg +1 -0
- polars2svg-0.1.0/tests/golden/histop_distribution_strip.svg +1 -0
- polars2svg-0.1.0/tests/golden/histop_multi_field_bin.svg +1 -0
- polars2svg-0.1.0/tests/golden/histop_no_draw_context.svg +1 -0
- polars2svg-0.1.0/tests/golden/histop_order_by_field.svg +1 -0
- polars2svg-0.1.0/tests/golden/histop_style_boxplot.svg +1 -0
- polars2svg-0.1.0/tests/golden/histop_style_stackedbar.svg +1 -0
- polars2svg-0.1.0/tests/golden/legend_histop_categorical_bottom.svg +1 -0
- polars2svg-0.1.0/tests/golden/legend_histop_colorbar_right.svg +1 -0
- polars2svg-0.1.0/tests/golden/legend_xyp_categorical_right.svg +9 -0
- polars2svg-0.1.0/tests/golden/legend_xyp_colorbar_bottom.svg +9 -0
- polars2svg-0.1.0/tests/golden/legend_xyp_colorbar_left.svg +9 -0
- polars2svg-0.1.0/tests/golden/legend_xyp_dict_top.svg +9 -0
- polars2svg-0.1.0/tests/golden/lines.svg +12 -0
- polars2svg-0.1.0/tests/golden/linkp_node_color_dict_single.svg +1 -0
- polars2svg-0.1.0/tests/golden/linkp_node_color_dict_three.svg +1 -0
- polars2svg-0.1.0/tests/golden/linkp_node_color_dict_two.svg +1 -0
- polars2svg-0.1.0/tests/golden/linkp_node_color_dict_unknown_key.svg +1 -0
- polars2svg-0.1.0/tests/golden/linkp_node_color_hex.svg +1 -0
- polars2svg-0.1.0/tests/golden/linkp_node_color_none.svg +1 -0
- polars2svg-0.1.0/tests/golden/no_context.svg +5 -0
- polars2svg-0.1.0/tests/golden/smallp_2x1_grid_with_remainder.svg +24 -0
- polars2svg-0.1.0/tests/golden/smallp_2x2_grid_include_all_no_collate_remainder.svg +45 -0
- polars2svg-0.1.0/tests/golden/smallp_2x2_grid_include_all_with_remainder.svg +47 -0
- polars2svg-0.1.0/tests/golden/smallp_2x2_grid_with_remainder.svg +42 -0
- polars2svg-0.1.0/tests/golden/smallp_basic_all_fit.svg +51 -0
- polars2svg-0.1.0/tests/golden/smallp_include_all_fits_exactly.svg +65 -0
- polars2svg-0.1.0/tests/golden/smallp_small_wxh_single_slot_all_remainder.svg +15 -0
- polars2svg-0.1.0/tests/golden/spreadlinesp_basic_ego_a.svg +1 -0
- polars2svg-0.1.0/tests/golden/spreadlinesp_count_field.svg +1 -0
- polars2svg-0.1.0/tests/golden/spreadlinesp_highlight_nodes.svg +1 -0
- polars2svg-0.1.0/tests/golden/spreadlinesp_node_color_field.svg +1 -0
- polars2svg-0.1.0/tests/golden/timep_linear_boxplot.svg +1 -0
- polars2svg-0.1.0/tests/golden/timep_linear_color_categorical.svg +1 -0
- polars2svg-0.1.0/tests/golden/timep_linear_color_numeric.svg +1 -0
- polars2svg-0.1.0/tests/golden/timep_linear_count_numeric.svg +1 -0
- polars2svg-0.1.0/tests/golden/timep_linear_crow_magnitude.svg +1 -0
- polars2svg-0.1.0/tests/golden/timep_linear_crow_stretched.svg +1 -0
- polars2svg-0.1.0/tests/golden/timep_linear_monthly.svg +1 -0
- polars2svg-0.1.0/tests/golden/timep_linear_stackedbar.svg +1 -0
- polars2svg-0.1.0/tests/golden/timep_no_draw_context.svg +1 -0
- polars2svg-0.1.0/tests/golden/timep_periodic_day_of_week.svg +1 -0
- polars2svg-0.1.0/tests/golden/timep_periodic_monthly.svg +1 -0
- polars2svg-0.1.0/tests/golden/variable_dot_size.svg +9 -0
- polars2svg-0.1.0/tests/golden_png/_tmp_test_color_none.png +0 -0
- polars2svg-0.1.0/tests/golden_png/basic_scatter.png +0 -0
- polars2svg-0.1.0/tests/golden_png/chordp_count_weight.png +0 -0
- polars2svg-0.1.0/tests/golden_png/chordp_default.png +0 -0
- polars2svg-0.1.0/tests/golden_png/chordp_draw_labels_radial.png +0 -0
- polars2svg-0.1.0/tests/golden_png/chordp_link_color_src.png +0 -0
- polars2svg-0.1.0/tests/golden_png/chordp_link_color_vary.png +0 -0
- polars2svg-0.1.0/tests/golden_png/chordp_link_shape_bundled.png +0 -0
- polars2svg-0.1.0/tests/golden_png/chordp_node_color_by_name.png +0 -0
- polars2svg-0.1.0/tests/golden_png/chordp_node_color_hex.png +0 -0
- polars2svg-0.1.0/tests/golden_png/chordp_node_selection.png +0 -0
- polars2svg-0.1.0/tests/golden_png/chordp_node_size_vary.png +0 -0
- polars2svg-0.1.0/tests/golden_png/color_categorical.png +0 -0
- polars2svg-0.1.0/tests/golden_png/color_continuous.png +0 -0
- polars2svg-0.1.0/tests/golden_png/distributions.png +0 -0
- polars2svg-0.1.0/tests/golden_png/histop_ascending_order.png +0 -0
- polars2svg-0.1.0/tests/golden_png/histop_basic_barchart.png +0 -0
- polars2svg-0.1.0/tests/golden_png/histop_color_categorical.png +0 -0
- polars2svg-0.1.0/tests/golden_png/histop_color_crow_magnitude.png +0 -0
- polars2svg-0.1.0/tests/golden_png/histop_color_crow_stretched.png +0 -0
- polars2svg-0.1.0/tests/golden_png/histop_color_numeric.png +0 -0
- polars2svg-0.1.0/tests/golden_png/histop_count_numeric_field.png +0 -0
- polars2svg-0.1.0/tests/golden_png/histop_distribution_strip.png +0 -0
- polars2svg-0.1.0/tests/golden_png/histop_multi_field_bin.png +0 -0
- polars2svg-0.1.0/tests/golden_png/histop_no_draw_context.png +0 -0
- polars2svg-0.1.0/tests/golden_png/histop_order_by_field.png +0 -0
- polars2svg-0.1.0/tests/golden_png/histop_style_boxplot.png +0 -0
- polars2svg-0.1.0/tests/golden_png/histop_style_stackedbar.png +0 -0
- polars2svg-0.1.0/tests/golden_png/legend_histop_categorical_bottom.png +0 -0
- polars2svg-0.1.0/tests/golden_png/legend_histop_colorbar_right.png +0 -0
- polars2svg-0.1.0/tests/golden_png/legend_xyp_categorical_right.png +0 -0
- polars2svg-0.1.0/tests/golden_png/legend_xyp_colorbar_bottom.png +0 -0
- polars2svg-0.1.0/tests/golden_png/legend_xyp_colorbar_left.png +0 -0
- polars2svg-0.1.0/tests/golden_png/legend_xyp_dict_top.png +0 -0
- polars2svg-0.1.0/tests/golden_png/lines.png +0 -0
- polars2svg-0.1.0/tests/golden_png/linkp_node_color_dict_single.png +0 -0
- polars2svg-0.1.0/tests/golden_png/linkp_node_color_dict_three.png +0 -0
- polars2svg-0.1.0/tests/golden_png/linkp_node_color_dict_two.png +0 -0
- polars2svg-0.1.0/tests/golden_png/linkp_node_color_dict_unknown_key.png +0 -0
- polars2svg-0.1.0/tests/golden_png/linkp_node_color_hex.png +0 -0
- polars2svg-0.1.0/tests/golden_png/linkp_node_color_none.png +0 -0
- polars2svg-0.1.0/tests/golden_png/no_context.png +0 -0
- polars2svg-0.1.0/tests/golden_png/smallp_2x1_grid_with_remainder.png +0 -0
- polars2svg-0.1.0/tests/golden_png/smallp_2x2_grid_include_all_no_collate_remainder.png +0 -0
- polars2svg-0.1.0/tests/golden_png/smallp_2x2_grid_include_all_with_remainder.png +0 -0
- polars2svg-0.1.0/tests/golden_png/smallp_2x2_grid_with_remainder.png +0 -0
- polars2svg-0.1.0/tests/golden_png/smallp_basic_all_fit.png +0 -0
- polars2svg-0.1.0/tests/golden_png/smallp_include_all_fits_exactly.png +0 -0
- polars2svg-0.1.0/tests/golden_png/smallp_small_wxh_single_slot_all_remainder.png +0 -0
- polars2svg-0.1.0/tests/golden_png/spreadlinesp_basic_ego_a.png +0 -0
- polars2svg-0.1.0/tests/golden_png/spreadlinesp_count_field.png +0 -0
- polars2svg-0.1.0/tests/golden_png/spreadlinesp_highlight_nodes.png +0 -0
- polars2svg-0.1.0/tests/golden_png/spreadlinesp_node_color_field.png +0 -0
- polars2svg-0.1.0/tests/golden_png/timep_linear_boxplot.png +0 -0
- polars2svg-0.1.0/tests/golden_png/timep_linear_color_categorical.png +0 -0
- polars2svg-0.1.0/tests/golden_png/timep_linear_color_numeric.png +0 -0
- polars2svg-0.1.0/tests/golden_png/timep_linear_count_numeric.png +0 -0
- polars2svg-0.1.0/tests/golden_png/timep_linear_crow_magnitude.png +0 -0
- polars2svg-0.1.0/tests/golden_png/timep_linear_crow_stretched.png +0 -0
- polars2svg-0.1.0/tests/golden_png/timep_linear_monthly.png +0 -0
- polars2svg-0.1.0/tests/golden_png/timep_linear_stackedbar.png +0 -0
- polars2svg-0.1.0/tests/golden_png/timep_no_draw_context.png +0 -0
- polars2svg-0.1.0/tests/golden_png/timep_periodic_day_of_week.png +0 -0
- polars2svg-0.1.0/tests/golden_png/timep_periodic_monthly.png +0 -0
- polars2svg-0.1.0/tests/golden_png/variable_dot_size.png +0 -0
- polars2svg-0.1.0/tests/histop_dataframes.py +36 -0
- polars2svg-0.1.0/tests/piep_dataframes.py +32 -0
- polars2svg-0.1.0/tests/random_dataframe.py +52 -0
- polars2svg-0.1.0/tests/svg_test_utils.py +162 -0
- polars2svg-0.1.0/tests/test_bar_chart_styles.py +129 -0
- polars2svg-0.1.0/tests/test_bar_chart_template.py +141 -0
- polars2svg-0.1.0/tests/test_bar_colorize_consistency.py +316 -0
- polars2svg-0.1.0/tests/test_changelog.py +59 -0
- polars2svg-0.1.0/tests/test_chordp_basic.py +323 -0
- polars2svg-0.1.0/tests/test_chordp_color.py +194 -0
- polars2svg-0.1.0/tests/test_chordp_golden.py +85 -0
- polars2svg-0.1.0/tests/test_chordp_interactive.py +211 -0
- polars2svg-0.1.0/tests/test_chordp_pos.py +363 -0
- polars2svg-0.1.0/tests/test_circle_packer.py +251 -0
- polars2svg-0.1.0/tests/test_color_overrides.py +103 -0
- polars2svg-0.1.0/tests/test_contributing.py +45 -0
- polars2svg-0.1.0/tests/test_convey_proximity_layout.py +118 -0
- polars2svg-0.1.0/tests/test_count_inert_warning.py +250 -0
- polars2svg-0.1.0/tests/test_cross_component_consistency.py +92 -0
- polars2svg-0.1.0/tests/test_crow_color_independence.py +110 -0
- polars2svg-0.1.0/tests/test_displaylist.py +228 -0
- polars2svg-0.1.0/tests/test_dtype_keyed_logging.py +352 -0
- polars2svg-0.1.0/tests/test_edge_case_inputs.py +312 -0
- polars2svg-0.1.0/tests/test_export_save.py +141 -0
- polars2svg-0.1.0/tests/test_gather_metrics.py +117 -0
- polars2svg-0.1.0/tests/test_global_config.py +221 -0
- polars2svg-0.1.0/tests/test_glyph_atlas.py +112 -0
- polars2svg-0.1.0/tests/test_hex_color_detection.py +195 -0
- polars2svg-0.1.0/tests/test_histop_basic.py +236 -0
- polars2svg-0.1.0/tests/test_histop_color.py +127 -0
- polars2svg-0.1.0/tests/test_histop_count.py +125 -0
- polars2svg-0.1.0/tests/test_histop_distribution_strip.py +364 -0
- polars2svg-0.1.0/tests/test_histop_exhaustive.py +75 -0
- polars2svg-0.1.0/tests/test_histop_extended.py +298 -0
- polars2svg-0.1.0/tests/test_histop_filter_by_rectangle.py +532 -0
- polars2svg-0.1.0/tests/test_histop_filter_by_substring.py +119 -0
- polars2svg-0.1.0/tests/test_histop_golden.py +160 -0
- polars2svg-0.1.0/tests/test_histop_order.py +124 -0
- polars2svg-0.1.0/tests/test_histop_smallp.py +95 -0
- polars2svg-0.1.0/tests/test_interactive_controller.py +1252 -0
- polars2svg-0.1.0/tests/test_laguerre_voronoi.py +372 -0
- polars2svg-0.1.0/tests/test_layout_protocol.py +65 -0
- polars2svg-0.1.0/tests/test_legend.py +429 -0
- polars2svg-0.1.0/tests/test_legend_golden.py +76 -0
- polars2svg-0.1.0/tests/test_linkp_basic.py +393 -0
- polars2svg-0.1.0/tests/test_linkp_color.py +130 -0
- polars2svg-0.1.0/tests/test_linkp_golden.py +75 -0
- polars2svg-0.1.0/tests/test_linkp_inert_params.py +89 -0
- polars2svg-0.1.0/tests/test_linkp_interactive.py +815 -0
- polars2svg-0.1.0/tests/test_linkp_labels.py +197 -0
- polars2svg-0.1.0/tests/test_linkp_stack_positioning.py +455 -0
- polars2svg-0.1.0/tests/test_mds_at_scale.py +190 -0
- polars2svg-0.1.0/tests/test_meta.py +29 -0
- polars2svg-0.1.0/tests/test_multifield_bin_collision.py +137 -0
- polars2svg-0.1.0/tests/test_no_data_placeholder.py +179 -0
- polars2svg-0.1.0/tests/test_optional_dependency_extras.py +139 -0
- polars2svg-0.1.0/tests/test_p2s.py +187 -0
- polars2svg-0.1.0/tests/test_p2s_colors_mixin.py +222 -0
- polars2svg-0.1.0/tests/test_p2s_geometry_mixin.py +94 -0
- polars2svg-0.1.0/tests/test_p2s_graph_mixin.py +856 -0
- polars2svg-0.1.0/tests/test_p2s_polars_mixin.py +73 -0
- polars2svg-0.1.0/tests/test_p2s_render.py +233 -0
- polars2svg-0.1.0/tests/test_p2s_render_colorize_order.py +107 -0
- polars2svg-0.1.0/tests/test_p2s_text_mixin.py +162 -0
- polars2svg-0.1.0/tests/test_p2s_tfields.py +228 -0
- polars2svg-0.1.0/tests/test_package_exports.py +49 -0
- polars2svg-0.1.0/tests/test_parse_consolidation.py +205 -0
- polars2svg-0.1.0/tests/test_performance.py +178 -0
- polars2svg-0.1.0/tests/test_piep_basic.py +531 -0
- polars2svg-0.1.0/tests/test_piep_smallp.py +121 -0
- polars2svg-0.1.0/tests/test_polars_force_directed_layout.py +151 -0
- polars2svg-0.1.0/tests/test_polars_mixin_no_eval.py +75 -0
- polars2svg-0.1.0/tests/test_positional_dispatch.py +143 -0
- polars2svg-0.1.0/tests/test_render_with.py +106 -0
- polars2svg-0.1.0/tests/test_reserved_columns.py +217 -0
- polars2svg-0.1.0/tests/test_security_automation.py +95 -0
- polars2svg-0.1.0/tests/test_singleton_init.py +122 -0
- polars2svg-0.1.0/tests/test_smallp_basic.py +105 -0
- polars2svg-0.1.0/tests/test_smallp_cycle_by.py +103 -0
- polars2svg-0.1.0/tests/test_smallp_geometry.py +197 -0
- polars2svg-0.1.0/tests/test_smallp_input_types.py +129 -0
- polars2svg-0.1.0/tests/test_smallp_order.py +169 -0
- polars2svg-0.1.0/tests/test_smallp_shared.py +569 -0
- polars2svg-0.1.0/tests/test_smallp_validation.py +142 -0
- polars2svg-0.1.0/tests/test_spreadlinepi.py +338 -0
- polars2svg-0.1.0/tests/test_spreadlinesp_basic.py +101 -0
- polars2svg-0.1.0/tests/test_spreadlinesp_golden.py +55 -0
- polars2svg-0.1.0/tests/test_spreadlinesp_packing.py +113 -0
- polars2svg-0.1.0/tests/test_stack_control.py +204 -0
- polars2svg-0.1.0/tests/test_svg_float_precision.py +165 -0
- polars2svg-0.1.0/tests/test_template_defaults.py +157 -0
- polars2svg-0.1.0/tests/test_template_state_isolation.py +189 -0
- polars2svg-0.1.0/tests/test_tfdp_backend.py +115 -0
- polars2svg-0.1.0/tests/test_tfdp_layout.py +199 -0
- polars2svg-0.1.0/tests/test_tfield_typed.py +323 -0
- polars2svg-0.1.0/tests/test_timep_basic.py +166 -0
- polars2svg-0.1.0/tests/test_timep_color.py +109 -0
- polars2svg-0.1.0/tests/test_timep_context.py +145 -0
- polars2svg-0.1.0/tests/test_timep_count.py +117 -0
- polars2svg-0.1.0/tests/test_timep_exhaustive.py +91 -0
- polars2svg-0.1.0/tests/test_timep_filter_by_rectangle.py +441 -0
- polars2svg-0.1.0/tests/test_timep_golden.py +193 -0
- polars2svg-0.1.0/tests/test_timep_smallp.py +105 -0
- polars2svg-0.1.0/tests/test_timep_time_fields.py +114 -0
- polars2svg-0.1.0/tests/test_typing_surface.py +87 -0
- polars2svg-0.1.0/tests/test_udist.py +121 -0
- polars2svg-0.1.0/tests/test_webgpu_components.py +366 -0
- polars2svg-0.1.0/tests/test_webgpu_histop.py +100 -0
- polars2svg-0.1.0/tests/test_webgpu_piep.py +95 -0
- polars2svg-0.1.0/tests/test_webgpu_xyp.py +137 -0
- polars2svg-0.1.0/tests/test_wxh_normalization.py +273 -0
- polars2svg-0.1.0/tests/test_xyp_background.py +205 -0
- polars2svg-0.1.0/tests/test_xyp_color.py +72 -0
- polars2svg-0.1.0/tests/test_xyp_distributions.py +68 -0
- polars2svg-0.1.0/tests/test_xyp_dot_size.py +60 -0
- polars2svg-0.1.0/tests/test_xyp_exhaustive.py +82 -0
- polars2svg-0.1.0/tests/test_xyp_filter_by_rectangle.py +200 -0
- polars2svg-0.1.0/tests/test_xyp_golden.py +119 -0
- polars2svg-0.1.0/tests/test_xyp_int_ranges.py +127 -0
- polars2svg-0.1.0/tests/test_xyp_label.py +86 -0
- polars2svg-0.1.0/tests/test_xyp_lines.py +89 -0
- polars2svg-0.1.0/tests/test_xyp_multiset_color.py +24 -0
- polars2svg-0.1.0/tests/test_xyp_order.py +59 -0
- polars2svg-0.1.0/tests/test_xyp_periodic_autobin.py +91 -0
- polars2svg-0.1.0/tests/test_xyp_periodic_time_contexts.py +255 -0
- polars2svg-0.1.0/tests/test_xyp_records_at.py +103 -0
- polars2svg-0.1.0/tests/test_xyp_supersample.py +242 -0
- polars2svg-0.1.0/tests/test_xyp_templates.py +16 -0
- polars2svg-0.1.0/tests/test_xyp_tfields.py +47 -0
- polars2svg-0.1.0/tests/test_xyp_transforms.py +86 -0
- polars2svg-0.1.0/tests/test_xyp_unhashable_spec.py +107 -0
- polars2svg-0.1.0/tests/test_xyp_xy_ranges.py +181 -0
- polars2svg-0.1.0/tests/timep_dataframes.py +57 -0
- polars2svg-0.1.0/tests/webgpu_test_utils.py +51 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
# Python dependencies (pyproject.toml: core deps, extras, and the dev
|
|
4
|
+
# dependency-group).
|
|
5
|
+
- package-ecosystem: "pip"
|
|
6
|
+
directory: "/"
|
|
7
|
+
schedule:
|
|
8
|
+
interval: "weekly"
|
|
9
|
+
|
|
10
|
+
# GitHub Actions used by ci.yml / release.yml.
|
|
11
|
+
- package-ecosystem: "github-actions"
|
|
12
|
+
directory: "/"
|
|
13
|
+
schedule:
|
|
14
|
+
interval: "weekly"
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
# Clean-room install verification on Linux (PyPI must-do #9).
|
|
4
|
+
# Every prior test run was macOS/arm64; this exercises the built wheel on
|
|
5
|
+
# linux/amd64 inside a stock python:3.13-slim image — a genuine clean room
|
|
6
|
+
# (no preinstalled project deps, no system Python packages) — to catch
|
|
7
|
+
# platform-dependent path handling, the mlx import guard, and font-metric
|
|
8
|
+
# non-determinism in the golden-image tests.
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
push:
|
|
12
|
+
branches: [main]
|
|
13
|
+
pull_request:
|
|
14
|
+
workflow_dispatch:
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
# Type-check the public surface (PyPI nice-to-have #1). The package ships a
|
|
18
|
+
# py.typed marker, so downstream checkers read our hints; this guards that the
|
|
19
|
+
# public signatures stay valid. The [tool.mypy] config in pyproject.toml relaxes
|
|
20
|
+
# the error codes that fire only on the library's internal dynamic idiom.
|
|
21
|
+
type-check:
|
|
22
|
+
name: mypy (public surface)
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v4
|
|
26
|
+
- name: Install uv
|
|
27
|
+
run: pip install --no-cache-dir uv
|
|
28
|
+
- name: Run mypy
|
|
29
|
+
run: uvx mypy polars2svg
|
|
30
|
+
|
|
31
|
+
# Security/quality automation (PyPI nice-to-have #5).
|
|
32
|
+
security-and-quality:
|
|
33
|
+
name: bandit + pip-audit + ruff
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
steps:
|
|
36
|
+
- uses: actions/checkout@v4
|
|
37
|
+
- uses: astral-sh/setup-uv@v5
|
|
38
|
+
|
|
39
|
+
- name: bandit (static security scan)
|
|
40
|
+
# Findings are either fixed or annotated in-line with a justified
|
|
41
|
+
# `# nosec <code> - <reason>` (see SECURITY.md's threat model for why
|
|
42
|
+
# e.g. random.randint()-based SVG id scoping and the background=
|
|
43
|
+
# shape-descriptor XML parsing are not vulnerabilities here). A clean
|
|
44
|
+
# run means every remaining flag has been reviewed and accepted.
|
|
45
|
+
run: uvx bandit -r polars2svg/
|
|
46
|
+
|
|
47
|
+
- name: pip-audit (known-vulnerable dependency scan)
|
|
48
|
+
# Audits the full resolved dependency graph (every extra + the dev
|
|
49
|
+
# group), not just what a bare `pip install polars2svg` pulls in —
|
|
50
|
+
# broader coverage than METADATA alone would give.
|
|
51
|
+
run: |
|
|
52
|
+
uv export --no-hashes --all-extras --group dev -o /tmp/requirements-audit.txt
|
|
53
|
+
uvx pip-audit -r /tmp/requirements-audit.txt
|
|
54
|
+
|
|
55
|
+
- name: ruff (E9, F)
|
|
56
|
+
# Minimal rule set on purpose — see the [tool.ruff] comment in
|
|
57
|
+
# pyproject.toml. Catches syntax errors and pyflakes issues (undefined
|
|
58
|
+
# names, unused imports/variables, duplicate dict keys) without
|
|
59
|
+
# fighting the codebase's distinctive style.
|
|
60
|
+
run: uvx ruff check polars2svg/
|
|
61
|
+
|
|
62
|
+
linux-cleanroom:
|
|
63
|
+
name: Linux clean-room wheel install + tests
|
|
64
|
+
runs-on: ubuntu-latest
|
|
65
|
+
container: python:3.13-slim
|
|
66
|
+
steps:
|
|
67
|
+
# git lets actions/checkout use a fast clone instead of the REST tarball.
|
|
68
|
+
- name: Install git
|
|
69
|
+
run: apt-get update && apt-get install -y --no-install-recommends git
|
|
70
|
+
|
|
71
|
+
- uses: actions/checkout@v4
|
|
72
|
+
|
|
73
|
+
- name: Build the wheel
|
|
74
|
+
run: |
|
|
75
|
+
pip install --no-cache-dir uv
|
|
76
|
+
uv build
|
|
77
|
+
|
|
78
|
+
- name: Install the built wheel into a clean environment
|
|
79
|
+
run: pip install --no-cache-dir dist/*.whl
|
|
80
|
+
|
|
81
|
+
- name: Import smoke test
|
|
82
|
+
run: python -c "import polars2svg; print('import ok')"
|
|
83
|
+
|
|
84
|
+
- name: Install test-only dependencies
|
|
85
|
+
# Mirrors the [dependency-groups] dev set that the wheel METADATA does
|
|
86
|
+
# not carry: pytest + the rasterization/kaggle test extras. rlPyCairo is
|
|
87
|
+
# reportlab 5.x's renderPM backend on Linux (macOS has its own); without
|
|
88
|
+
# it svglib rasterization errors out. The PNG-RMS golden tests skip off
|
|
89
|
+
# macOS regardless, but the backend is needed for any that force-run.
|
|
90
|
+
run: pip install --no-cache-dir pytest kagglehub svglib reportlab rlPyCairo
|
|
91
|
+
|
|
92
|
+
- name: Run the test suite
|
|
93
|
+
# test_performance.py needs a machine-local baseline (gitignored);
|
|
94
|
+
# kaggle-backed t-field tests need network/credentials. Both excluded,
|
|
95
|
+
# matching must-do #9.
|
|
96
|
+
run: python -m pytest tests/ -q --ignore=tests/test_performance.py -k 'not tfield'
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Build the mkdocs site and deploy it to GitHub Pages.
|
|
2
|
+
#
|
|
3
|
+
# The site builds from static, committed content (the example SVGs are
|
|
4
|
+
# generated locally by docs/gen_examples.py), so this job does not need
|
|
5
|
+
# polars2svg installed. Once the package source is mirrored into this repo /
|
|
6
|
+
# published to PyPI, add an install step here and an mkdocstrings API page.
|
|
7
|
+
#
|
|
8
|
+
# Requires: repo Settings → Pages → Source = "GitHub Actions".
|
|
9
|
+
name: docs
|
|
10
|
+
|
|
11
|
+
on:
|
|
12
|
+
push:
|
|
13
|
+
branches: [main]
|
|
14
|
+
workflow_dispatch:
|
|
15
|
+
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
pages: write
|
|
19
|
+
id-token: write
|
|
20
|
+
|
|
21
|
+
concurrency:
|
|
22
|
+
group: pages
|
|
23
|
+
cancel-in-progress: true
|
|
24
|
+
|
|
25
|
+
jobs:
|
|
26
|
+
build:
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@v4
|
|
30
|
+
- uses: actions/setup-python@v5
|
|
31
|
+
with:
|
|
32
|
+
python-version: '3.13'
|
|
33
|
+
- name: Install mkdocs-material
|
|
34
|
+
run: pip install --no-cache-dir mkdocs-material
|
|
35
|
+
- name: Build site
|
|
36
|
+
run: mkdocs build --strict
|
|
37
|
+
- uses: actions/configure-pages@v5
|
|
38
|
+
- uses: actions/upload-pages-artifact@v3
|
|
39
|
+
with:
|
|
40
|
+
path: site
|
|
41
|
+
|
|
42
|
+
deploy:
|
|
43
|
+
needs: build
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
environment:
|
|
46
|
+
name: github-pages
|
|
47
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
48
|
+
steps:
|
|
49
|
+
- id: deployment
|
|
50
|
+
uses: actions/deploy-pages@v4
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Publishes polars2svg to PyPI via Trusted Publishing (OIDC) on release tags.
|
|
4
|
+
#
|
|
5
|
+
# This is NOT continuous integration: it runs only when a tag matching v*
|
|
6
|
+
# is pushed (e.g. `git tag v0.1.0 && git push origin v0.1.0`), so it does
|
|
7
|
+
# not run the test suite on every commit (see PyPI must-do #11 — CI-on-every-
|
|
8
|
+
# commit is intentionally disabled; local/standalone-server runs cover testing).
|
|
9
|
+
#
|
|
10
|
+
# One-time setup the maintainer must do (an agent cannot): register this repo
|
|
11
|
+
# as a Trusted Publisher on PyPI. Before the project exists, add it as a
|
|
12
|
+
# "pending publisher" in your PyPI account:
|
|
13
|
+
# https://pypi.org/manage/account/publishing/
|
|
14
|
+
# with workflow name `release.yml` and environment name `pypi`. This replaces
|
|
15
|
+
# the twine + API-token flow that used to live in pypi_instructions.txt.
|
|
16
|
+
|
|
17
|
+
on:
|
|
18
|
+
push:
|
|
19
|
+
tags: ['v*']
|
|
20
|
+
workflow_dispatch:
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
build:
|
|
24
|
+
name: Build sdist + wheel
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v4
|
|
28
|
+
|
|
29
|
+
- name: Install uv
|
|
30
|
+
uses: astral-sh/setup-uv@v5
|
|
31
|
+
|
|
32
|
+
- name: Build distributions
|
|
33
|
+
run: uv build
|
|
34
|
+
|
|
35
|
+
- name: Check distribution metadata
|
|
36
|
+
run: uvx twine check dist/*
|
|
37
|
+
|
|
38
|
+
- name: Upload distributions
|
|
39
|
+
uses: actions/upload-artifact@v4
|
|
40
|
+
with:
|
|
41
|
+
name: dist
|
|
42
|
+
path: dist/
|
|
43
|
+
|
|
44
|
+
publish:
|
|
45
|
+
name: Publish to PyPI
|
|
46
|
+
needs: build
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
# Trusted Publishing: no API token/secret. PyPI verifies the OIDC identity
|
|
49
|
+
# of this workflow running in the `pypi` environment.
|
|
50
|
+
environment:
|
|
51
|
+
name: pypi
|
|
52
|
+
url: https://pypi.org/project/polars2svg/
|
|
53
|
+
permissions:
|
|
54
|
+
id-token: write
|
|
55
|
+
steps:
|
|
56
|
+
- name: Download distributions
|
|
57
|
+
uses: actions/download-artifact@v4
|
|
58
|
+
with:
|
|
59
|
+
name: dist
|
|
60
|
+
path: dist/
|
|
61
|
+
|
|
62
|
+
- name: Publish to PyPI
|
|
63
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
coverage.json
|
|
54
|
+
|
|
55
|
+
# Translations
|
|
56
|
+
*.mo
|
|
57
|
+
*.pot
|
|
58
|
+
|
|
59
|
+
# Django stuff:
|
|
60
|
+
*.log
|
|
61
|
+
local_settings.py
|
|
62
|
+
db.sqlite3
|
|
63
|
+
db.sqlite3-journal
|
|
64
|
+
|
|
65
|
+
# Flask stuff:
|
|
66
|
+
instance/
|
|
67
|
+
.webassets-cache
|
|
68
|
+
|
|
69
|
+
# Scrapy stuff:
|
|
70
|
+
.scrapy
|
|
71
|
+
|
|
72
|
+
# Sphinx documentation
|
|
73
|
+
docs/_build/
|
|
74
|
+
|
|
75
|
+
# PyBuilder
|
|
76
|
+
.pybuilder/
|
|
77
|
+
target/
|
|
78
|
+
|
|
79
|
+
# Jupyter Notebook
|
|
80
|
+
.ipynb_checkpoints
|
|
81
|
+
|
|
82
|
+
# IPython
|
|
83
|
+
profile_default/
|
|
84
|
+
ipython_config.py
|
|
85
|
+
|
|
86
|
+
# pyenv
|
|
87
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
88
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
89
|
+
# .python-version
|
|
90
|
+
|
|
91
|
+
# pipenv
|
|
92
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
93
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
94
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
95
|
+
# install all needed dependencies.
|
|
96
|
+
#Pipfile.lock
|
|
97
|
+
|
|
98
|
+
# UV
|
|
99
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
100
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
101
|
+
# commonly ignored for libraries.
|
|
102
|
+
#uv.lock
|
|
103
|
+
# uv.toml holds machine-local resolver settings (exclude-newer); keep it out of VCS.
|
|
104
|
+
uv.toml
|
|
105
|
+
|
|
106
|
+
# poetry
|
|
107
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
108
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
109
|
+
# commonly ignored for libraries.
|
|
110
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
111
|
+
#poetry.lock
|
|
112
|
+
#poetry.toml
|
|
113
|
+
|
|
114
|
+
# pdm
|
|
115
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
116
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
117
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
118
|
+
#pdm.lock
|
|
119
|
+
#pdm.toml
|
|
120
|
+
.pdm-python
|
|
121
|
+
.pdm-build/
|
|
122
|
+
|
|
123
|
+
# pixi
|
|
124
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
125
|
+
#pixi.lock
|
|
126
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
127
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
128
|
+
.pixi
|
|
129
|
+
|
|
130
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
131
|
+
__pypackages__/
|
|
132
|
+
|
|
133
|
+
# Celery stuff
|
|
134
|
+
celerybeat-schedule
|
|
135
|
+
celerybeat.pid
|
|
136
|
+
|
|
137
|
+
# SageMath parsed files
|
|
138
|
+
*.sage.py
|
|
139
|
+
|
|
140
|
+
# Environments
|
|
141
|
+
.env
|
|
142
|
+
.envrc
|
|
143
|
+
.venv
|
|
144
|
+
env/
|
|
145
|
+
venv/
|
|
146
|
+
ENV/
|
|
147
|
+
env.bak/
|
|
148
|
+
venv.bak/
|
|
149
|
+
|
|
150
|
+
# Spyder project settings
|
|
151
|
+
.spyderproject
|
|
152
|
+
.spyproject
|
|
153
|
+
|
|
154
|
+
# Rope project settings
|
|
155
|
+
.ropeproject
|
|
156
|
+
|
|
157
|
+
# mkdocs documentation
|
|
158
|
+
/site
|
|
159
|
+
|
|
160
|
+
# mypy
|
|
161
|
+
.mypy_cache/
|
|
162
|
+
.dmypy.json
|
|
163
|
+
dmypy.json
|
|
164
|
+
|
|
165
|
+
# Pyre type checker
|
|
166
|
+
.pyre/
|
|
167
|
+
|
|
168
|
+
# pytype static type analyzer
|
|
169
|
+
.pytype/
|
|
170
|
+
|
|
171
|
+
# Cython debug symbols
|
|
172
|
+
cython_debug/
|
|
173
|
+
|
|
174
|
+
# PyCharm
|
|
175
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
176
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
177
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
178
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
179
|
+
#.idea/
|
|
180
|
+
|
|
181
|
+
# Abstra
|
|
182
|
+
# Abstra is an AI-powered process automation framework.
|
|
183
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
184
|
+
# Learn more at https://abstra.io/docs
|
|
185
|
+
.abstra/
|
|
186
|
+
|
|
187
|
+
# Visual Studio Code
|
|
188
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
189
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
190
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
191
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
192
|
+
# .vscode/
|
|
193
|
+
|
|
194
|
+
# Ruff stuff:
|
|
195
|
+
.ruff_cache/
|
|
196
|
+
|
|
197
|
+
# PyPI configuration file
|
|
198
|
+
.pypirc
|
|
199
|
+
|
|
200
|
+
# Cursor
|
|
201
|
+
# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
|
|
202
|
+
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
|
|
203
|
+
# refer to https://docs.cursor.com/context/ignore-files
|
|
204
|
+
.cursorignore
|
|
205
|
+
.cursorindexingignore
|
|
206
|
+
|
|
207
|
+
# Marimo
|
|
208
|
+
marimo/_static/
|
|
209
|
+
marimo/_lsp/
|
|
210
|
+
__marimo__/
|
|
211
|
+
coverage_reports/20260212_2230_coverage.json
|
|
212
|
+
|
|
213
|
+
# Claude
|
|
214
|
+
.claude
|
|
215
|
+
# CLAUDE.md
|
|
216
|
+
# *.md
|
|
217
|
+
|
|
218
|
+
# Performance baseline (machine-specific, auto-generated by test_performance.py)
|
|
219
|
+
tests/perf_baseline.json
|
|
220
|
+
|
|
221
|
+
graphify-out/
|
|
222
|
+
.DS_Store
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to **polars2svg** are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **`TFDPLayout` now runs on NVIDIA GPUs via MLX's CUDA backend.** The layout was
|
|
13
|
+
previously documented and packaged as Apple-silicon-only. MLX ships an official
|
|
14
|
+
CUDA backend, and the eight t-FDP compute kernels are backend-agnostic
|
|
15
|
+
`mlx.core` — so the same code runs on Metal or CUDA with **no change to the
|
|
16
|
+
math**. New `[mlx-cuda]` / `[mlx-cuda13]` extras install it (Linux only; NVIDIA
|
|
17
|
+
SM ≥ 7.5, driver ≥ 550.54.14, glibc ≥ 2.35).
|
|
18
|
+
- **`polars2svg.gpu_backend()`** — reports which backend `TFDPLayout` resolved to:
|
|
19
|
+
`'metal'`, `'cuda'`, or `'cpu'`.
|
|
20
|
+
- **`tests/test_tfdp_backend.py`** — exercises each MLX op t-FDP depends on
|
|
21
|
+
(broadcast all-pairs diff, gather, `.at[].add()` scatter-add with duplicate
|
|
22
|
+
indices, keyed RNG) directly on the resolved device, so a backend gap fails by
|
|
23
|
+
name. Plus GPU-vs-CPU cross-check, convergence, and finiteness tests in
|
|
24
|
+
`test_tfdp_layout.py`.
|
|
25
|
+
|
|
26
|
+
- **Legends and colorbars: opt-in `legend=` on every rendered component**
|
|
27
|
+
(`xyp`, `histop`, `timep`, `piep`, `linkp`, `chordp`, `spreadlinesp`;
|
|
28
|
+
`smallp` panels inherit it from their template component). Layered value:
|
|
29
|
+
`legend=True` (≡ `'right'`), a position string
|
|
30
|
+
(`'right' | 'left' | 'top' | 'bottom'`), or a dict
|
|
31
|
+
(`{'pos', 'title', 'fmt', 'max_items', 'order'}`). The legend **kind is
|
|
32
|
+
auto-selected** from the resolved color mode — a categorical swatch list
|
|
33
|
+
for `CSETp`/bare-categorical color, a colorbar for the spectrum modes —
|
|
34
|
+
and the strip is reserved **from** `wxh` (the plot region shrinks; the
|
|
35
|
+
physical output size is unchanged). A truthy `legend` with nothing to
|
|
36
|
+
legend (flat/fixed color) silently renders nothing, so
|
|
37
|
+
`set_defaults(legend=True)` is safe as a global default. Legends are
|
|
38
|
+
recorded into the shared `DisplayList`, so SVG **and** WebGPU outputs both
|
|
39
|
+
carry them, and the captured scale/category metadata is exposed as
|
|
40
|
+
`component.legend_info` (a `polars2svg.LegendInfo`). v1 scope is the color
|
|
41
|
+
encoding only (no size legends yet). The default `legend=False` renders
|
|
42
|
+
byte-identically to previous output.
|
|
43
|
+
|
|
44
|
+
### Fixed
|
|
45
|
+
|
|
46
|
+
- **`pip install polars2svg[mlx]` was broken.** `tfdp_layout.py` imports
|
|
47
|
+
`scipy`/`networkx`/`scikit-learn`, but the `mlx` extra did not chain `[layouts]`
|
|
48
|
+
(as `interactive` does), so the extra resolved to an install whose only module
|
|
49
|
+
could not import. `mlx` now chains `polars2svg[layouts]`.
|
|
50
|
+
|
|
51
|
+
### Changed
|
|
52
|
+
|
|
53
|
+
- `TFDPLayout` no longer hardcodes `device=mx.gpu`. It probes the GPU once and
|
|
54
|
+
falls back to the CPU device with a one-time warning if none is usable — the
|
|
55
|
+
plain Linux MLX wheel has no GPU backend, which would otherwise have failed at
|
|
56
|
+
the first kernel.
|
|
57
|
+
|
|
58
|
+
- **Slimmed the core install; added `[layouts]` and `[interactive]` extras.**
|
|
59
|
+
`pip install polars2svg` now pulls only `polars`, `numpy`, `pyarrow`,
|
|
60
|
+
`pillow`, and `platformdirs` — enough for `xyp`, `histop`, `timep`, `piep`,
|
|
61
|
+
`smallp`, and `spreadlinesp`. `networkx`, `scikit-learn`, `scipy`, `shapely`,
|
|
62
|
+
and `squarify` move to the new `polars2svg[layouts]` extra (needed by
|
|
63
|
+
`linkp`'s/`chordp`'s pluggable layouts, the graph-layout mixin, and
|
|
64
|
+
shapely-typed `background=` shapes on `xyp`/`linkp`); `panel`,
|
|
65
|
+
`jupyter_bokeh`, and `param` move to `polars2svg[interactive]` (which
|
|
66
|
+
includes `layouts`, since the interactive graph views need it too).
|
|
67
|
+
`polars2svg[all]` restores the previous "batteries included" install.
|
|
68
|
+
Calling a component that needs a missing extra (`chordp()`, `panelize()`,
|
|
69
|
+
`xypi()`, a graph-layout mixin method, `background=` shapes) now raises a
|
|
70
|
+
clear `ImportError` naming the extra to install, rather than either
|
|
71
|
+
succeeding silently or failing with a bare `ModuleNotFoundError` — this
|
|
72
|
+
breaks nothing at runtime as long as the extra is installed, but is a
|
|
73
|
+
**breaking change to the default install** if you were relying on
|
|
74
|
+
`linkp`/`chordp`/interactive variants working out of the box with a bare
|
|
75
|
+
`pip install polars2svg`.
|
|
76
|
+
|
|
77
|
+
## [0.1.0] — 2026-07-10
|
|
78
|
+
|
|
79
|
+
Initial public release: Polars-native DataFrame → SVG visualizations for Jupyter.
|
|
80
|
+
Pass a Polars `DataFrame` straight to a component and get a crisp, self-contained
|
|
81
|
+
SVG back. Every component also has a linked, interactive variant (built on Panel)
|
|
82
|
+
for brushing and cross-filtering in a notebook, plus optional WebGPU rendering for
|
|
83
|
+
large frames.
|
|
84
|
+
|
|
85
|
+
### Added
|
|
86
|
+
|
|
87
|
+
- **Component roster** — eight rendered components, each a method on a
|
|
88
|
+
`Polars2SVG` instance:
|
|
89
|
+
- `xyp` — scatter / distribution plot (numeric or categorical x/y).
|
|
90
|
+
- `histop` — horizontal histogram bars, one per category/bin.
|
|
91
|
+
- `timep` — temporal bar chart with linear or periodic (day-of-week, month, …)
|
|
92
|
+
time modes.
|
|
93
|
+
- `linkp` — node-link graph / network with pluggable layouts.
|
|
94
|
+
- `chordp` — chord diagram of weighted flows around a circle.
|
|
95
|
+
- `piep` — pie chart.
|
|
96
|
+
- `spreadlinesp` — egocentric radial "spread" rings for influence/propagation.
|
|
97
|
+
- `smallp` — small multiples: a grid of one template component faceted by a field.
|
|
98
|
+
- **Interactive, cross-linked variants** — `xypi`, `histopi`, `timepi`, `linkpi`,
|
|
99
|
+
`smallpi` (and peers) sharing the static signatures, composed into a dashboard
|
|
100
|
+
with `panelize(layout)` for brushing and cross-filtering in a notebook.
|
|
101
|
+
- **WebGPU rendering** — pass `use_webgpu=True` to render through WebGPU for large
|
|
102
|
+
frames; a `webgpu()` / `gpuDisplayList()` path exists across all components.
|
|
103
|
+
- **Orthogonal `count=` / `color=` encoding** — a shared aggregation rule for
|
|
104
|
+
`count=` (row count, sum, distinct-count, struct distinct-count) and a
|
|
105
|
+
dtype-keyed `color=` inference (numeric → magnitude spectrum, otherwise
|
|
106
|
+
categorical), with enums (`SCALARp`, `SETp`, `CSETp`, `CMAGNITUDE_SUMp`,
|
|
107
|
+
`CROW_MAGNITUDEp`, `CROW_STRETCHEDp`, …) to pin intent explicitly.
|
|
108
|
+
- **T-fields** — `p2s.tField(column, enum)` for time-transformation fields
|
|
109
|
+
(returns a frozen `TField` `str` subclass); the legacy `'column|suffix'` string
|
|
110
|
+
form still works with a one-time deprecation warning.
|
|
111
|
+
- **Pluggable layout classes** exported from the package: `PolarsForceDirectedLayout`,
|
|
112
|
+
`ConveyProximityLayout`, `LandmarkMDSLayout`, `PivotMDSLayout`, `TFDPLayout`
|
|
113
|
+
(all satisfy the `LayoutAlgorithm` protocol via `.results()`).
|
|
114
|
+
- **Export API** — `save(path)` / `savePNG(path)` on every rendered component;
|
|
115
|
+
SVG save has no extra dependency, PNG rasterization is behind the `[export]`
|
|
116
|
+
extra (`svglib`, `reportlab`, `rlPyCairo`).
|
|
117
|
+
- **Typed package** — ships a `py.typed` marker with type hints on the public
|
|
118
|
+
surface (constructor, component factories, `tField`, `panelize`, layout classes).
|
|
119
|
+
- **Exception hierarchy** — `Polars2SVGError` base with `InvalidSpecError` and
|
|
120
|
+
`DataError` subclasses, all exported from the package.
|
|
121
|
+
- **`__version__`** attribute, read from installed package metadata.
|
|
122
|
+
- **Optional extras** — `[mlx]` (Apple-silicon MLX-accelerated force-directed
|
|
123
|
+
layout) and `[export]` (PNG rasterization).
|
|
124
|
+
- **Diagnostic INFO logging** through the `polars2svg_logger` for dtype-keyed
|
|
125
|
+
`count=`/`color=` inference choices (off by default).
|
|
126
|
+
- **SECURITY.md** documenting the SVG-injection threat model (row-data label text
|
|
127
|
+
is HTML-escaped; component configuration is trusted).
|
|
128
|
+
|
|
129
|
+
[Unreleased]: https://github.com/datrcode/polars2svg/compare/v0.1.0...HEAD
|
|
130
|
+
[0.1.0]: https://github.com/datrcode/polars2svg/releases/tag/v0.1.0
|