plotcli-py 0.1.0__py3-none-any.whl
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.
- CLAUDE.md +51 -0
- LICENSE +21 -0
- PKG-INFO +358 -0
- README.md +340 -0
- main.py +6 -0
- plotcli-original/.Rbuildignore +18 -0
- plotcli-original/.github/workflows/deploy_docs.yml +43 -0
- plotcli-original/.gitignore +46 -0
- plotcli-original/DESCRIPTION +25 -0
- plotcli-original/NAMESPACE +60 -0
- plotcli-original/NEWS.md +112 -0
- plotcli-original/R/ascii_escape.r +13 -0
- plotcli-original/R/canvas.r +586 -0
- plotcli-original/R/class_functions.r +114 -0
- plotcli-original/R/geom_registry.r +1376 -0
- plotcli-original/R/ggplotcli.r +234 -0
- plotcli-original/R/ggplotcli_helpers.r +1099 -0
- plotcli-original/R/helper_functions.r +351 -0
- plotcli-original/R/plotcli.r +963 -0
- plotcli-original/R/plotcli_grid.r +1 -0
- plotcli-original/R/plotcli_wrappers.r +416 -0
- plotcli-original/R/zzz.r +15 -0
- plotcli-original/README.md +192 -0
- plotcli-original/docs/ascii.png +0 -0
- plotcli-original/docs/bar.png +0 -0
- plotcli-original/docs/block.png +0 -0
- plotcli-original/docs/boxplot.png +0 -0
- plotcli-original/docs/density.png +0 -0
- plotcli-original/docs/facet.png +0 -0
- plotcli-original/docs/facet_grid.png +0 -0
- plotcli-original/docs/generate_png.sh +137 -0
- plotcli-original/docs/heatmap.png +0 -0
- plotcli-original/docs/histogram.png +0 -0
- plotcli-original/docs/line.png +0 -0
- plotcli-original/docs/noborder.png +0 -0
- plotcli-original/docs/scatter.png +0 -0
- plotcli-original/docs/showcase.R +182 -0
- plotcli-original/inst/doc/ggplotcli.R +231 -0
- plotcli-original/inst/doc/ggplotcli.Rmd +329 -0
- plotcli-original/inst/doc/ggplotcli.html +1078 -0
- plotcli-original/inst/doc/plotcli_class.R +98 -0
- plotcli-original/inst/doc/plotcli_class.Rmd +121 -0
- plotcli-original/inst/doc/plotcli_class.html +564 -0
- plotcli-original/inst/doc/plotcli_wrappers.R +35 -0
- plotcli-original/inst/doc/plotcli_wrappers.Rmd +62 -0
- plotcli-original/inst/doc/plotcli_wrappers.html +546 -0
- plotcli-original/man/AsciiCanvas.Rd +116 -0
- plotcli-original/man/BlockCanvas.Rd +132 -0
- plotcli-original/man/BrailleCanvas.Rd +146 -0
- plotcli-original/man/Canvas.Rd +492 -0
- plotcli-original/man/GeomRegistry.Rd +9 -0
- plotcli-original/man/add_legend_to_output.Rd +12 -0
- plotcli-original/man/braille_dot_bit.Rd +29 -0
- plotcli-original/man/braille_set_dot.Rd +21 -0
- plotcli-original/man/bresenham.Rd +27 -0
- plotcli-original/man/build_plot_output.Rd +28 -0
- plotcli-original/man/build_plot_output_v2.Rd +41 -0
- plotcli-original/man/cat_plot_matrix.Rd +17 -0
- plotcli-original/man/cbind.plotcli.Rd +19 -0
- plotcli-original/man/cbind_plots.Rd +17 -0
- plotcli-original/man/color_to_term.Rd +18 -0
- plotcli-original/man/create_canvas.Rd +21 -0
- plotcli-original/man/create_panel_scales.Rd +29 -0
- plotcli-original/man/create_scales.Rd +27 -0
- plotcli-original/man/dot-geom_registry.Rd +16 -0
- plotcli-original/man/draw_border.Rd +12 -0
- plotcli-original/man/draw_grid.Rd +12 -0
- plotcli-original/man/extract_legend_info.Rd +12 -0
- plotcli-original/man/extract_plot_labels.Rd +12 -0
- plotcli-original/man/extract_plot_style.Rd +12 -0
- plotcli-original/man/format_axis_label.Rd +18 -0
- plotcli-original/man/format_four_chars.Rd +21 -0
- plotcli-original/man/geom_area_handler.Rd +12 -0
- plotcli-original/man/geom_bar_handler.Rd +12 -0
- plotcli-original/man/geom_boxplot_handler.Rd +13 -0
- plotcli-original/man/geom_density_handler.Rd +12 -0
- plotcli-original/man/geom_histogram_handler.Rd +12 -0
- plotcli-original/man/geom_hline_handler.Rd +12 -0
- plotcli-original/man/geom_line_handler.Rd +12 -0
- plotcli-original/man/geom_path_handler.Rd +12 -0
- plotcli-original/man/geom_point_handler.Rd +12 -0
- plotcli-original/man/geom_rect_handler.Rd +12 -0
- plotcli-original/man/geom_segment_handler.Rd +12 -0
- plotcli-original/man/geom_smooth_handler.Rd +12 -0
- plotcli-original/man/geom_text_handler.Rd +12 -0
- plotcli-original/man/geom_vline_handler.Rd +12 -0
- plotcli-original/man/get_color_hue.Rd +18 -0
- plotcli-original/man/get_data_subset.Rd +23 -0
- plotcli-original/man/get_facet_info.Rd +18 -0
- plotcli-original/man/get_geom_handler.Rd +17 -0
- plotcli-original/man/get_term_colors.Rd +21 -0
- plotcli-original/man/ggplotcli.Rd +83 -0
- plotcli-original/man/init_color_mapping.Rd +15 -0
- plotcli-original/man/is_braille.Rd +20 -0
- plotcli-original/man/is_geom_registered.Rd +17 -0
- plotcli-original/man/list_registered_geoms.Rd +14 -0
- plotcli-original/man/make_colored.Rd +23 -0
- plotcli-original/man/make_unique_names.Rd +20 -0
- plotcli-original/man/normalize_data.Rd +27 -0
- plotcli-original/man/pclib.Rd +48 -0
- plotcli-original/man/pclibx.Rd +46 -0
- plotcli-original/man/pclid.Rd +44 -0
- plotcli-original/man/pclih.Rd +50 -0
- plotcli-original/man/pclil.Rd +48 -0
- plotcli-original/man/pclis.Rd +48 -0
- plotcli-original/man/pixel_to_braille.Rd +23 -0
- plotcli-original/man/plotcli.Rd +598 -0
- plotcli-original/man/plotcli_bar.Rd +48 -0
- plotcli-original/man/plotcli_box.Rd +46 -0
- plotcli-original/man/plotcli_density.Rd +44 -0
- plotcli-original/man/plotcli_histogram.Rd +50 -0
- plotcli-original/man/plotcli_line.Rd +48 -0
- plotcli-original/man/plotcli_options.Rd +18 -0
- plotcli-original/man/plotcli_scatter.Rd +48 -0
- plotcli-original/man/plus-.plotcli.Rd +19 -0
- plotcli-original/man/rbind.plotcli.Rd +19 -0
- plotcli-original/man/rbind_plots.Rd +17 -0
- plotcli-original/man/register_geom.Rd +21 -0
- plotcli-original/man/remove_color_codes.Rd +21 -0
- plotcli-original/man/render_faceted_plot.Rd +25 -0
- plotcli-original/man/render_single_panel.Rd +12 -0
- plotcli-original/man/safe_aes_name.Rd +18 -0
- plotcli-original/tests/testthat/test-new-geoms.R +136 -0
- plotcli-original/tests/testthat/test-plotcli.R +69 -0
- plotcli-original/tests/testthat.R +4 -0
- plotcli-original/vignettes/ggplotcli.Rmd +329 -0
- plotcli-original/vignettes/plotcli_class.R +98 -0
- plotcli-original/vignettes/plotcli_class.Rmd +121 -0
- plotcli-original/vignettes/plotcli_wrappers.R +35 -0
- plotcli-original/vignettes/plotcli_wrappers.Rmd +62 -0
- plotcli.egg-info/PKG-INFO +11 -0
- plotcli.egg-info/SOURCES.txt +7 -0
- plotcli.egg-info/dependency_links.txt +1 -0
- plotcli.egg-info/entry_points.txt +3 -0
- plotcli.egg-info/top_level.txt +1 -0
- plotcli.py +978 -0
- plotcli_py-0.1.0.dist-info/METADATA +358 -0
- plotcli_py-0.1.0.dist-info/RECORD +143 -0
- plotcli_py-0.1.0.dist-info/WHEEL +4 -0
- plotcli_py-0.1.0.dist-info/entry_points.txt +2 -0
- plotcli_py-0.1.0.dist-info/licenses/LICENSE +21 -0
- pyproject.toml +31 -0
- uv.lock +8 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
#' Get data subset for a specific geom
|
|
2
|
+
#'
|
|
3
|
+
#' This function returns a subset of the data for a specific geom.
|
|
4
|
+
#'
|
|
5
|
+
#' @param geom_name The name of the geom for which the data subset is needed.
|
|
6
|
+
#' @param data The data to be subsetted.
|
|
7
|
+
#' @param aes The aesthetic mappings for the geom.
|
|
8
|
+
#' @param p_build The ggplot build object.
|
|
9
|
+
#' @return A list containing the data subset for the specified geom.
|
|
10
|
+
#' @export
|
|
11
|
+
get_data_subset <- function(geom_name, data, aes, p_build) {
|
|
12
|
+
|
|
13
|
+
out = data
|
|
14
|
+
|
|
15
|
+
if (geom_name == "GeomDensity") {
|
|
16
|
+
density_data <- density(data[[rlang::as_name(aes$x)]])
|
|
17
|
+
out = list(x = density_data$x, y = density_data$y)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if(geom_name == "GeomSmooth") out =list(x = p_build$data[[2]]$x, y = p_build$data[[2]]$y)
|
|
21
|
+
|
|
22
|
+
if(geom_name %in% c("GeomBoxplot")) {
|
|
23
|
+
|
|
24
|
+
out$y = data[[rlang::as_name(aes$x)]]
|
|
25
|
+
out$x = rep(1, length(out$y))
|
|
26
|
+
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if(!geom_name %in% c("GeomDensity", "GeomSmooth", "GeomBoxplot", "GeomBar")) {
|
|
30
|
+
|
|
31
|
+
out$x = data[[rlang::as_name(aes$x)]]
|
|
32
|
+
out$y = data[[rlang::as_name(aes$y)]]
|
|
33
|
+
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return(out)
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
#' Safely extract aesthetic name from ggplot mapping
|
|
41
|
+
#'
|
|
42
|
+
#' Handles quosures, simple symbols, and calls like factor(cyl)
|
|
43
|
+
#'
|
|
44
|
+
#' @param aes_expr The aesthetic expression (can be a quosure)
|
|
45
|
+
#' @return Character string of the column name, or NULL
|
|
46
|
+
#' @keywords internal
|
|
47
|
+
safe_aes_name <- function(aes_expr) {
|
|
48
|
+
if (is.null(aes_expr)) return(NULL)
|
|
49
|
+
|
|
50
|
+
# If it's a quosure, extract the expression
|
|
51
|
+
if (rlang::is_quosure(aes_expr)) {
|
|
52
|
+
aes_expr <- rlang::quo_get_expr(aes_expr)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# If it's a simple symbol, use as_name
|
|
56
|
+
if (rlang::is_symbol(aes_expr)) {
|
|
57
|
+
return(rlang::as_name(aes_expr))
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# If it's a call (like factor(cyl)), try to extract the first argument
|
|
61
|
+
if (rlang::is_call(aes_expr)) {
|
|
62
|
+
# Get the call arguments
|
|
63
|
+
args <- rlang::call_args(aes_expr)
|
|
64
|
+
if (length(args) > 0) {
|
|
65
|
+
# Recursively try to get the name from the first argument
|
|
66
|
+
return(safe_aes_name(args[[1]]))
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
# Fallback: try to deparse and clean up
|
|
71
|
+
tryCatch({
|
|
72
|
+
# Last resort: deparse the expression
|
|
73
|
+
deparsed <- deparse(aes_expr)
|
|
74
|
+
# Try to extract column name from factor(col) or similar
|
|
75
|
+
if (grepl("^\\w+\\((.+)\\)$", deparsed)) {
|
|
76
|
+
return(gsub("^\\w+\\((.+)\\)$", "\\1", deparsed))
|
|
77
|
+
}
|
|
78
|
+
return(deparsed)
|
|
79
|
+
}, error = function(e) {
|
|
80
|
+
return(NULL)
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
#' ggplotcli - Render ggplot2 objects in the terminal
|
|
85
|
+
#'
|
|
86
|
+
#' Convert any ggplot2 plot to a terminal-based visualization using Unicode
|
|
87
|
+
#' Braille characters or ASCII. Supports 15+ geom types, faceting, themes,
|
|
88
|
+
#' and color aesthetics.
|
|
89
|
+
#'
|
|
90
|
+
#' @param p A ggplot2 object to render
|
|
91
|
+
#' @param width Character width of the plot (default: 60)
|
|
92
|
+
#' @param height Character height of the plot (default: 20)
|
|
93
|
+
#' @param canvas_type Type of canvas: "braille" (high-res), "block" (medium), or "ascii" (basic). Default: "braille"
|
|
94
|
+
#' @param border Draw border around plot. "auto" uses ggplot theme, or TRUE/FALSE (default: "auto")
|
|
95
|
+
#' @param grid Grid lines: "none", "major", "minor", "both", or "auto" (default: "none")
|
|
96
|
+
#' @param show_axes Whether to show axis values (default: TRUE)
|
|
97
|
+
#' @param axis_labels Whether to show axis labels from ggplot (default: TRUE)
|
|
98
|
+
#' @param legend Legend display: "auto", "right", "bottom", "none" (default: "auto")
|
|
99
|
+
#' @param title_align Title alignment: "center" or "left" (default: "center")
|
|
100
|
+
#' @param subtitle Whether to show subtitle (default: TRUE)
|
|
101
|
+
#' @param caption Whether to show caption (default: TRUE)
|
|
102
|
+
#' @param title Optional title override (NULL uses ggplot title)
|
|
103
|
+
#' @param boxplot_style Style for boxplots: "ascii" uses box-drawing characters (default),
|
|
104
|
+
#' "braille" uses Braille dots like other geoms
|
|
105
|
+
#'
|
|
106
|
+
#' @return Invisibly returns the canvas object
|
|
107
|
+
#' @export
|
|
108
|
+
#'
|
|
109
|
+
#' @examples
|
|
110
|
+
#' library(ggplot2)
|
|
111
|
+
#'
|
|
112
|
+
#' # Basic scatter plot
|
|
113
|
+
#' p <- ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point()
|
|
114
|
+
#' ggplotcli(p)
|
|
115
|
+
#'
|
|
116
|
+
#' # With styling
|
|
117
|
+
#' ggplotcli(p, border = TRUE, grid = "major")
|
|
118
|
+
#'
|
|
119
|
+
#' # Faceted plot
|
|
120
|
+
#' p <- ggplot(mtcars, aes(x = wt, y = mpg)) +
|
|
121
|
+
#' geom_point() +
|
|
122
|
+
#' facet_wrap(~cyl)
|
|
123
|
+
#' ggplotcli(p, width = 70, height = 16)
|
|
124
|
+
#'
|
|
125
|
+
#' # Multiple geoms
|
|
126
|
+
#' p <- ggplot(mtcars, aes(x = mpg)) +
|
|
127
|
+
#' geom_histogram(aes(y = after_stat(density)), bins = 10) +
|
|
128
|
+
#' geom_density(color = "red")
|
|
129
|
+
#' ggplotcli(p)
|
|
130
|
+
ggplotcli <- function(p,
|
|
131
|
+
width = 60,
|
|
132
|
+
height = 20,
|
|
133
|
+
canvas_type = "braille",
|
|
134
|
+
border = "auto",
|
|
135
|
+
grid = "none",
|
|
136
|
+
show_axes = TRUE,
|
|
137
|
+
axis_labels = TRUE,
|
|
138
|
+
legend = "auto",
|
|
139
|
+
title_align = "center",
|
|
140
|
+
subtitle = TRUE,
|
|
141
|
+
caption = TRUE,
|
|
142
|
+
title = NULL,
|
|
143
|
+
boxplot_style = "ascii") {
|
|
144
|
+
|
|
145
|
+
# Build the plot to get computed data
|
|
146
|
+
built <- ggplot2::ggplot_build(p)
|
|
147
|
+
|
|
148
|
+
# Initialize color mapping for all colors in the plot (including legend colors)
|
|
149
|
+
# This ensures we minimize color repetition across groups and consistent legend
|
|
150
|
+
all_colors <- c()
|
|
151
|
+
for (layer_data in built$data) {
|
|
152
|
+
if ("colour" %in% names(layer_data)) {
|
|
153
|
+
all_colors <- c(all_colors, layer_data$colour)
|
|
154
|
+
}
|
|
155
|
+
if ("fill" %in% names(layer_data)) {
|
|
156
|
+
all_colors <- c(all_colors, layer_data$fill)
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
# Also include legend colors for consistent mapping
|
|
161
|
+
# Helper to extract colors from a scale (handles both discrete and continuous)
|
|
162
|
+
get_scale_colors <- function(scale, n) {
|
|
163
|
+
colors <- tryCatch(scale$palette(n), error = function(e) NULL)
|
|
164
|
+
if (is.null(colors) || (length(colors) == 1 && is.na(colors[1])) ||
|
|
165
|
+
all(is.na(colors))) {
|
|
166
|
+
colors <- tryCatch(scale$palette(seq(0, 1, length.out = n)), error = function(e) NULL)
|
|
167
|
+
}
|
|
168
|
+
colors
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
# Get legend colors from colour scale
|
|
172
|
+
color_scale <- built$plot$scales$get_scales("colour")
|
|
173
|
+
if (!is.null(color_scale)) {
|
|
174
|
+
tryCatch({
|
|
175
|
+
breaks <- color_scale$get_breaks()
|
|
176
|
+
n <- length(breaks)
|
|
177
|
+
if (n > 0) {
|
|
178
|
+
legend_cols <- get_scale_colors(color_scale, n)
|
|
179
|
+
if (!is.null(legend_cols) && !all(is.na(legend_cols))) {
|
|
180
|
+
all_colors <- c(all_colors, legend_cols)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}, error = function(e) NULL)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
# Get legend colors from fill scale
|
|
187
|
+
fill_scale <- built$plot$scales$get_scales("fill")
|
|
188
|
+
if (!is.null(fill_scale)) {
|
|
189
|
+
tryCatch({
|
|
190
|
+
breaks <- fill_scale$get_breaks()
|
|
191
|
+
n <- length(breaks)
|
|
192
|
+
if (n > 0) {
|
|
193
|
+
legend_cols <- get_scale_colors(fill_scale, n)
|
|
194
|
+
if (!is.null(legend_cols) && !all(is.na(legend_cols))) {
|
|
195
|
+
all_colors <- c(all_colors, legend_cols)
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}, error = function(e) NULL)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
init_color_mapping(unique(all_colors))
|
|
202
|
+
|
|
203
|
+
# Extract styling from ggplot theme
|
|
204
|
+
style <- extract_plot_style(built, border, grid, legend)
|
|
205
|
+
|
|
206
|
+
# Get plot labels
|
|
207
|
+
labels <- extract_plot_labels(built, title, subtitle, caption, axis_labels)
|
|
208
|
+
|
|
209
|
+
# Create style options object
|
|
210
|
+
style_opts <- list(
|
|
211
|
+
border = style$border,
|
|
212
|
+
grid = style$grid,
|
|
213
|
+
show_axes = show_axes,
|
|
214
|
+
axis_labels = axis_labels,
|
|
215
|
+
legend = style$legend,
|
|
216
|
+
title_align = title_align,
|
|
217
|
+
labels = labels,
|
|
218
|
+
boxplot_style = boxplot_style
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
# Check for faceting
|
|
222
|
+
layout <- built$layout
|
|
223
|
+
|
|
224
|
+
facet_info <- get_facet_info(layout)
|
|
225
|
+
|
|
226
|
+
if (facet_info$has_facets) {
|
|
227
|
+
# Render faceted plot
|
|
228
|
+
render_faceted_plot(built, facet_info, width, height, canvas_type,
|
|
229
|
+
style_opts)
|
|
230
|
+
} else {
|
|
231
|
+
# Render single panel plot
|
|
232
|
+
render_single_panel(built, width, height, canvas_type, style_opts)
|
|
233
|
+
}
|
|
234
|
+
}
|