diff --git a/3rdparty/tiff/Makefile b/3rdparty/tiff/Makefile index 782ae1100..6eae5c95f 100644 --- a/3rdparty/tiff/Makefile +++ b/3rdparty/tiff/Makefile @@ -2,7 +2,7 @@ ifeq ($(strip $(PREFIX)),) override PREFIX = $(abspath $(CURDIR)/../build) endif -VERSION = 4.5.1 +VERSION = 4.7.0 TIFF_EXTRA_CONFIGURE_FLAGS ?= ifeq ($(shell uname),Darwin) TIFF_EXTRA_CONFIGURE_FLAGS += CFLAGS=-mmacosx-version-min=10.15 diff --git a/CMakeLists.txt b/CMakeLists.txt index 522c23cab..c79ec66b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,7 @@ set(GR_DIRECTORY CACHE STRING "Default value for GRDIR" ) option(GR_BUILD_DEMOS "Build demos for GR" OFF) +option(GR_BUILD_GKSM "Build GKS metafile reader for GR" OFF) option(GR_INSTALL "Create installation target for GR" ON) option(GR_USE_BUNDLED_LIBRARIES "Use thirdparty libraries bundled with GR" OFF) option(GR_MANUAL_MOC_AND_RCC "Manually run moc and rcc instead of relying on AUTOMOC and AUTORCC" OFF) @@ -1243,6 +1244,8 @@ if((Qt6Widgets_FOUND lib/grm/grplot/gredit/Bounding_logic.cpp lib/grm/grplot/gredit/Bounding_object.cpp lib/grm/grplot/gredit/CustomTreeWidgetItem.cpp + lib/grm/grplot/gredit/EditElementWidget.cpp + lib/grm/grplot/gredit/TableWidget.cpp lib/grm/grplot/gredit/TreeWidget.cpp lib/grm/grplot/grplot.cxx lib/grm/grplot/grplot_mainwindow.cxx @@ -1353,15 +1356,33 @@ if((Qt6Widgets_FOUND ${CMAKE_CURRENT_BINARY_DIR}/moc_AddElementWidget.cpp DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/lib/grm/grplot/gredit/AddElementWidget.h ) + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/moc_EditElementWidget.cpp + COMMAND + ${QT_MOC_EXECUTABLE} -DGRDIR=\"$(GR_DIRECTORY)\" ${MOC_INCLUDE_FLAGS} + ${CMAKE_CURRENT_SOURCE_DIR}/lib/grm/grplot/gredit/EditElementWidget.h -o + ${CMAKE_CURRENT_BINARY_DIR}/moc_EditElementWidget.cpp + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/lib/grm/grplot/gredit/EditElementWidget.h + ) + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/moc_TableWidget.cpp + COMMAND + ${QT_MOC_EXECUTABLE} -DGRDIR=\"$(GR_DIRECTORY)\" ${MOC_INCLUDE_FLAGS} + ${CMAKE_CURRENT_SOURCE_DIR}/lib/grm/grplot/gredit/TableWidget.h -o + ${CMAKE_CURRENT_BINARY_DIR}/moc_TableWidget.cpp + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/lib/grm/grplot/gredit/TableWidget.h + ) target_sources( grplot PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/moc_grplot_mainwindow.cxx ${CMAKE_CURRENT_BINARY_DIR}/moc_grplot_widget.cxx + ${CMAKE_CURRENT_BINARY_DIR}/moc_AddElementWidget.cpp ${CMAKE_CURRENT_BINARY_DIR}/moc_Bounding_logic.cpp ${CMAKE_CURRENT_BINARY_DIR}/moc_Bounding_object.cpp ${CMAKE_CURRENT_BINARY_DIR}/moc_CustomTreeWidgetItem.cpp + ${CMAKE_CURRENT_BINARY_DIR}/moc_EditElementWidget.cpp + ${CMAKE_CURRENT_BINARY_DIR}/moc_TableWidget.cpp ${CMAKE_CURRENT_BINARY_DIR}/moc_TreeWidget.cpp - ${CMAKE_CURRENT_BINARY_DIR}/moc_AddElementWidget.cpp ${CMAKE_CURRENT_BINARY_DIR}/moc_grm_args_t_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/moc_receiver_thread.cpp ) @@ -1371,11 +1392,13 @@ if((Qt6Widgets_FOUND grplot PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/lib/grm/grplot/grplot_mainwindow.hxx ${CMAKE_CURRENT_SOURCE_DIR}/lib/grm/grplot/grplot_widget.hxx + ${CMAKE_CURRENT_SOURCE_DIR}/lib/grm/grplot/gredit/AddElementWidget.h ${CMAKE_CURRENT_SOURCE_DIR}/lib/grm/grplot/gredit/Bounding_logic.h ${CMAKE_CURRENT_SOURCE_DIR}/lib/grm/grplot/gredit/Bounding_object.h ${CMAKE_CURRENT_SOURCE_DIR}/lib/grm/grplot/gredit/CustomTreeWidgetItem.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/grm/grplot/gredit/EditElementWidget.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/grm/grplot/gredit/TableWidget.h ${CMAKE_CURRENT_SOURCE_DIR}/lib/grm/grplot/gredit/TreeWidget.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/grm/grplot/gredit/AddElementWidget.h ${CMAKE_CURRENT_SOURCE_DIR}/lib/grm/grplot/qtterm/grm_args_t_wrapper.h ${CMAKE_CURRENT_SOURCE_DIR}/lib/grm/grplot/qtterm/receiver_thread.h ) @@ -1418,6 +1441,13 @@ if(GR_BUILD_DEMOS) add_subdirectory(lib/grm/test/internal_api/grm grm_test_internal_api) endif() +if(GR_BUILD_GKSM) + add_executable(gksm lib/gks/gksm.c) + target_link_libraries(gksm PUBLIC gks_static) + target_compile_options(gksm PRIVATE ${COMPILER_OPTION_ERROR_IMPLICIT}) + set_target_properties(gksm PROPERTIES C_STANDARD 90 C_EXTENSIONS OFF C_STANDARD_REQUIRED ON) +endif() + if(GR_INSTALL) install(FILES LICENSE.md DESTINATION ${CMAKE_INSTALL_DOCDIR}/) install( diff --git a/lib/gks/dl.c b/lib/gks/dl.c index ac87aec1d..097293fdc 100644 --- a/lib/gks/dl.c +++ b/lib/gks/dl.c @@ -319,7 +319,8 @@ void gks_dl_write_item(gks_display_list_t *d, int fctid, int dx, int dy, int dim COPY(f_arr_1, sizeof(double)); break; - case 32: /* set character up vector */ + case 32: /* set character up vector */ + case 212: /* set clip sector */ len = 2 * sizeof(int) + 2 * sizeof(double); if (d->nbytes + len > d->size) reallocate(d, len); @@ -551,7 +552,7 @@ int gks_dl_read_item(char *dl, gks_state_list_t **gkss, break; case 32: /* set character up vector */ - case 252: /* move selection */ + case 212: /* set clip sector */ RESOLVE(r1, double, sizeof(double)); RESOLVE(r2, double, sizeof(double)); break; @@ -585,6 +586,11 @@ int gks_dl_read_item(char *dl, gks_state_list_t **gkss, case 251: /* end selection */ break; + + case 252: /* move selection */ + RESOLVE(r1, double, sizeof(double)); + RESOLVE(r2, double, sizeof(double)); + break; } switch (*fctid) @@ -696,6 +702,10 @@ int gks_dl_read_item(char *dl, gks_state_list_t **gkss, case 211: (*gkss)->clip_region = ia[0]; break; + case 212: + (*gkss)->clip_start_angle = r1[0]; + (*gkss)->clip_end_angle = r2[0]; + break; } fn(*fctid, *dx, *dy, *dimx, ia, 0, r1, 0, r2, *lc, chars, (void **)gkss); diff --git a/lib/gks/error.c b/lib/gks/error.c index 16f9a60cb..cee8fcc3c 100644 --- a/lib/gks/error.c +++ b/lib/gks/error.c @@ -278,6 +278,9 @@ const char *gks_function_name(int routine) case 211: name = "SET_CLIP_REGION"; break; + case 212: + name = "SET_CLIP_SECTOR"; + break; case 250: name = "BEGIN_SELECTION"; break; @@ -476,6 +479,9 @@ void gks_report_error(int routine, int errnum) case 165: message = "Clip region type is invalid in routine %s"; break; + case 166: + message = "Clip sector angles are invalid in routine %s"; + break; case 401: message = "Dimensions of image are invalid in routine %s"; break; diff --git a/lib/gks/gks.c b/lib/gks/gks.c index e4dc71c66..23ba6c2ed 100644 --- a/lib/gks/gks.c +++ b/lib/gks/gks.c @@ -539,8 +539,10 @@ void gks_init_gks(void) s->bwidth = 1; s->bcoli = 0; s->clip_tnr = 0; - s->resize_behaviour = GKS_K_RESIZE; s->clip_region = GKS_K_REGION_RECTANGLE; + s->clip_start_angle = 0; + s->clip_end_angle = 360; + s->resize_behaviour = GKS_K_RESIZE; s->aspect_ratio = 1; s->callback = NULL; @@ -4556,6 +4558,35 @@ void gks_inq_clip_region(int *errind, int *region) *region = s->clip_region; } +void gks_set_clip_sector(double start_angle, double end_angle) +{ + if (state >= GKS_K_GKOP) + { + if (start_angle >= 0 && end_angle > start_angle && end_angle <= 360) + { + s->clip_start_angle = f_arr_1[0] = start_angle; + s->clip_end_angle = f_arr_2[0] = end_angle; + + /* call the device driver link routine */ + gks_ddlk(SET_CLIP_SECTOR, 0, 0, 0, i_arr, 1, f_arr_1, 1, f_arr_2, 0, c_arr, NULL); + } + else + /* clip sector angles are invalid */ + gks_report_error(SET_CLIP_SECTOR, 166); + } + else + /* GKS not in proper state. GKS must be in one of the states + GKOP, WSOP, WSAC or SGOP */ + gks_report_error(SET_CLIP_SECTOR, 8); +} + +void gks_inq_clip_sector(int *errind, double *start_angle, double *end_angle) +{ + *errind = GKS_K_NO_ERROR; + *start_angle = s->clip_start_angle; + *end_angle = s->clip_end_angle; +} + void gks_set_resize_behaviour(int flag) { if (state >= GKS_K_GKOP) diff --git a/lib/gks/gks.h b/lib/gks/gks.h index c712a6c50..ea2e45009 100644 --- a/lib/gks/gks.h +++ b/lib/gks/gks.h @@ -709,6 +709,9 @@ DLLEXPORT void gks_inq_resize_behaviour(int *flag); DLLEXPORT void gks_set_clip_region(int region); DLLEXPORT void gks_inq_clip_region(int *errind, int *region); +DLLEXPORT void gks_set_clip_sector(double start_angle, double end_angle); +DLLEXPORT void gks_inq_clip_sector(int *errind, double *start_angle, double *end_angle); + /* Entry point definitions */ #define gsetlinecolorind gsetlinecolourind diff --git a/lib/gks/gkscore.h b/lib/gks/gkscore.h index e207de038..cb32f414c 100644 --- a/lib/gks/gkscore.h +++ b/lib/gks/gkscore.h @@ -116,6 +116,7 @@ extern "C" { #define INQ_WS_STATE 209 #define SAMPLE_LOCATOR 210 #define SET_CLIP_REGION 211 +#define SET_CLIP_SECTOR 212 #define BEGIN_SELECTION 250 #define END_SELECTION 251 @@ -170,9 +171,10 @@ typedef struct double bwidth; int bcoli; int clip_tnr; + int clip_region; + double clip_start_angle, clip_end_angle; int resize_behaviour; double aspect_ratio; - int clip_region; char *(*callback)(const char *); int debug; } gks_state_list_t; diff --git a/lib/gks/mf.c b/lib/gks/mf.c index 4dba5d6ea..ed35222a7 100644 --- a/lib/gks/mf.c +++ b/lib/gks/mf.c @@ -179,7 +179,8 @@ static void write_item(int fctid, int dx, int dy, int dimx, int *i_arr, int len_ COPY(f_arr_1, sizeof(double)); break; - case 32: /* set character up vector */ + case 32: /* set character up vector */ + case 212: /* set clip sector */ len = 2 * sizeof(int) + 2 * sizeof(double); if (p->nbytes + len > p->size) reallocate(len); @@ -389,6 +390,7 @@ void gks_drv_mo(int fctid, int dx, int dy, int dimx, int *i_arr, int len_farr_1, case 207: case 208: case 211: + case 212: if (p->state == GKS_K_WS_ACTIVE) { @@ -575,7 +577,8 @@ static void interp(char *str) RESOLVE(f_arr_1, double, sizeof(double)); break; - case 32: /* set character up vector */ + case 32: /* set character up vector */ + case 212: /* set clip sector */ RESOLVE(f_arr_1, double, sizeof(double)); RESOLVE(f_arr_2, double, sizeof(double)); @@ -760,6 +763,9 @@ static void interp(char *str) case 211: gks_set_clip_region(i_arr[0]); break; + case 212: + gks_set_clip_sector(f_arr_1[0], f_arr_2[0]); + break; } RESOLVE(len, int, sizeof(int)); diff --git a/lib/gks/pdf.c b/lib/gks/pdf.c index fc8301dd9..bba517e5f 100644 --- a/lib/gks/pdf.c +++ b/lib/gks/pdf.c @@ -880,29 +880,89 @@ static void open_ws(int fd, int wstype) pdf_open(fd); } -static void set_clip(double *clrt) +static void arc(double x, double y, double w, double h, double a1, double a2) +{ + double bcp, cos_a1, cos_a2, sin_a1, sin_a2; + + a1 = a1 * M_PI / 180; + a2 = a2 * M_PI / 180; + + bcp = (4.0 / 3 * (1 - cos(0.5 * (a2 - a1))) / sin(0.5 * (a2 - a1))); + + sin_a1 = sin(a1); + sin_a2 = sin(a2); + cos_a1 = cos(a1); + cos_a2 = cos(a2); + + pdf_printf(p->content, "%.2f %.2f %.2f %.2f %.2f %.2f c\n", x + w * (cos_a1 - bcp * sin_a1), + y + h * (sin_a1 + bcp * cos_a1), x + w * (cos_a2 + bcp * sin_a2), y + h * (sin_a2 - bcp * cos_a2), + x + w * cos_a2, y + h * sin_a2); +} + +static void draw_arc(double x, double y, double w, double h, double a1, double a2) +{ + if (a1 == a2) return; + + while (fabs(a2 - a1) > 90 + 0.1) + { + if (a2 > a1) + { + arc(x, y, w, h, a1, a1 + 90); + a1 += 90; + } + else + { + arc(x, y, w, h, a1, a1 - 90); + a1 -= 90; + } + } + + if (a1 != a2) arc(x, y, w, h, a1, a2); +} + +static void set_clip_rect(int tnr) { - double x0, x1, y0, y1; + double *clrt, x0, x1, y0, y1; int curve, i; double x, y, xr, yr; + if (gkss->clip_tnr != 0) + clrt = gkss->viewport[gkss->clip_tnr]; + else if (gkss->clip == GKS_K_CLIP) + clrt = gkss->viewport[tnr]; + else + clrt = gkss->viewport[0]; + NDC_to_DC(clrt[0], clrt[2], x0, y0); NDC_to_DC(clrt[1], clrt[3], x1, y1); - if (gkss->clip_region == GKS_K_REGION_ELLIPSE && (gkss->clip_tnr != 0 || gkss->clip == GKS_K_CLIP)) + if (gkss->clip_region == GKS_K_REGION_ELLIPSE) { x = 0.5 * (x0 + x1); y = 0.5 * (y0 + y1); xr = 0.5 * (x1 - x0); yr = 0.5 * (y1 - y0); - pdf_moveto(p, x - xr * cx[3][2], y - yr * cy[3][2]); - for (curve = 0; curve < 4; curve++) + if (gkss->clip_start_angle > 0 || gkss->clip_end_angle < 360) + { + double w, h; + w = xr; + h = yr; + pdf_moveto(p, x + w * cos(gkss->clip_start_angle * M_PI / 180), + y + h * sin(gkss->clip_start_angle * M_PI / 180)); + draw_arc(x, y, w, h, gkss->clip_start_angle, gkss->clip_end_angle); + pdf_lineto(p, x, y); + } + else { - for (i = 0; i < 3; i++) + pdf_moveto(p, x - xr * cx[3][2], y - yr * cy[3][2]); + for (curve = 0; curve < 4; curve++) { - pdf_point(p, x - xr * cx[curve][i], y - yr * cy[curve][i]); + for (i = 0; i < 3; i++) + { + pdf_point(p, x - xr * cx[curve][i], y - yr * cy[curve][i]); + } + pdf_curveto(p); } - pdf_curveto(p); } } else @@ -1047,20 +1107,14 @@ static void polyline(int n, double *px, double *py) set_transparency(p->alpha); set_color(ln_color); - if (gkss->clip_tnr != 0) - { - pdf_save(p); - set_clip(gkss->viewport[gkss->clip_tnr]); - } + pdf_save(p); + set_clip_rect(gkss->cntnr); gks_set_dev_xform(gkss, p->window, p->viewport); gks_emul_polyline(n, px, py, ln_type, gkss->cntnr, move, draw); stroke(); - if (gkss->clip_tnr != 0) - { - pdf_restore(p); - } + pdf_restore(p); } static void draw_marker(double xn, double yn, int mtype, double mscale, int mcolor) @@ -1260,18 +1314,12 @@ static void polymarker(int n, double *px, double *py) set_linetype(GKS_K_LINETYPE_SOLID, 1.0); set_transparency(p->alpha); - if (gkss->clip_tnr != 0) - { - pdf_save(p); - set_clip(gkss->viewport[gkss->clip_tnr]); - } + pdf_save(p); + set_clip_rect(gkss->cntnr); marker_routine(n, px, py, mk_type, mk_size, mk_color); - if (gkss->clip_tnr != 0) - { - pdf_restore(p); - } + pdf_restore(p); } static void set_font(int font) @@ -1391,11 +1439,8 @@ static void text(double px, double py, int nchars, char *chars) if (tx_prec != GKS_K_TEXT_PRECISION_STROKE) set_font(tx_font); - if (gkss->clip_tnr != 0) - { - pdf_save(p); - set_clip(gkss->viewport[gkss->clip_tnr]); - } + pdf_save(p); + set_clip_rect(gkss->cntnr); if (tx_prec == GKS_K_TEXT_PRECISION_STRING) { @@ -1409,10 +1454,7 @@ static void text(double px, double py, int nchars, char *chars) gks_emul_text(px, py, nchars, chars, line_routine, fill_routine); } - if (gkss->clip_tnr != 0) - { - pdf_restore(p); - } + pdf_restore(p); } static void fill_routine(int n, double *px, double *py, int tnr) @@ -1485,18 +1527,12 @@ static void fillarea(int n, double *px, double *py) set_transparency(p->alpha); set_color(fl_color); - if (gkss->clip_tnr != 0) - { - pdf_save(p); - set_clip(gkss->viewport[gkss->clip_tnr]); - } + pdf_save(p); + set_clip_rect(gkss->cntnr); line_routine(n, px, py, DrawBorder, gkss->cntnr); - if (gkss->clip_tnr != 0) - { - pdf_restore(p); - } + pdf_restore(p); } else if (fl_inter == GKS_K_INTSTYLE_SOLID) { @@ -1504,14 +1540,7 @@ static void fillarea(int n, double *px, double *py) set_fillcolor(fl_color); pdf_save(p); - if (gkss->clip_tnr != 0) - { - set_clip(gkss->viewport[gkss->clip_tnr]); - } - else - { - set_clip(gkss->viewport[gkss->clip == GKS_K_CLIP ? gkss->cntnr : 0]); - } + set_clip_rect(gkss->cntnr); fill_routine(n, px, py, gkss->cntnr); @@ -1527,14 +1556,7 @@ static void fillarea(int n, double *px, double *py) p->pattern = fl_style; pdf_save(p); - if (gkss->clip_tnr != 0) - { - set_clip(gkss->viewport[gkss->clip_tnr]); - } - else - { - set_clip(gkss->viewport[gkss->clip == GKS_K_CLIP ? gkss->cntnr : 0]); - } + set_clip_rect(gkss->cntnr); fill_routine(n, px, py, gkss->cntnr); @@ -1586,14 +1608,7 @@ static void cellarray(double xmin, double xmax, double ymin, double ymax, int dx set_transparency(p->alpha); pdf_save(p); - if (gkss->clip_tnr != 0) - { - set_clip(gkss->viewport[gkss->clip_tnr]); - } - else - { - set_clip(gkss->viewport[gkss->clip == GKS_K_CLIP ? gkss->cntnr : 0]); - } + set_clip_rect(gkss->cntnr); have_alpha = 0; if (true_color) @@ -1727,46 +1742,6 @@ static void to_DC(int n, double *x, double *y) } } -static void arc(double x, double y, double w, double h, double a1, double a2) -{ - double bcp, cos_a1, cos_a2, sin_a1, sin_a2; - - a1 = a1 * M_PI / 180; - a2 = a2 * M_PI / 180; - - bcp = (4.0 / 3 * (1 - cos(0.5 * (a2 - a1))) / sin(0.5 * (a2 - a1))); - - sin_a1 = sin(a1); - sin_a2 = sin(a2); - cos_a1 = cos(a1); - cos_a2 = cos(a2); - - pdf_printf(p->content, "%.2f %.2f %.2f %.2f %.2f %.2f c\n", x + w * (cos_a1 - bcp * sin_a1), - y + h * (sin_a1 + bcp * cos_a1), x + w * (cos_a2 + bcp * sin_a2), y + h * (sin_a2 - bcp * cos_a2), - x + w * cos_a2, y + h * sin_a2); -} - -static void draw_arc(double x, double y, double w, double h, double a1, double a2) -{ - if (a1 == a2) return; - - while (fabs(a2 - a1) > 90) - { - if (a2 > a1) - { - arc(x, y, w, h, a1, a1 + 90); - a1 += 90; - } - else - { - arc(x, y, w, h, a1, a1 - 90); - a1 -= 90; - } - } - - if (a1 != a2) arc(x, y, w, h, a1, a2); -} - static void draw_path(int n, double *px, double *py, int nc, int *codes) { int i, j; @@ -2069,11 +2044,9 @@ static void fill_polygons(int n, double *px, double *py, int nply, int *ply) static void gdp(int n, double *px, double *py, int primid, int nc, int *codes) { - if (gkss->clip_tnr != 0) - { - pdf_save(p); - set_clip(gkss->viewport[gkss->clip_tnr]); - } + pdf_save(p); + set_clip_rect(gkss->cntnr); + set_linetype(GKS_K_LINETYPE_SOLID, 1.0); switch (primid) { @@ -2096,10 +2069,8 @@ static void gdp(int n, double *px, double *py, int primid, int nc, int *codes) gks_perror("invalid drawing primitive ('%d')", primid); exit(1); } - if (gkss->clip_tnr != 0) - { - pdf_restore(p); - } + + pdf_restore(p); } #ifndef EMSCRIPTEN diff --git a/lib/gks/plugin/cairoplugin.c b/lib/gks/plugin/cairoplugin.c index 4f494e07f..b5715d2d7 100644 --- a/lib/gks/plugin/cairoplugin.c +++ b/lib/gks/plugin/cairoplugin.c @@ -816,30 +816,38 @@ static void set_clip_rect(int tnr) cairo_reset_clip(p->cr); - if (gkss->clip_tnr != 0 || gkss->clip == GKS_K_CLIP) + if (gkss->clip_tnr != 0) + tnr = gkss->clip_tnr; + else if (gkss->clip == GKS_K_NOCLIP) + tnr = 0; + + x = p->rect[tnr][0][0]; + y = p->rect[tnr][0][1]; + w = p->rect[tnr][1][0] - p->rect[tnr][0][0]; + h = p->rect[tnr][1][1] - p->rect[tnr][0][1]; + + if (gkss->clip_region == GKS_K_REGION_ELLIPSE) { - if (gkss->clip_tnr != 0) - { - tnr = gkss->clip_tnr; - } - x = p->rect[tnr][0][0]; - y = p->rect[tnr][0][1]; - w = p->rect[tnr][1][0] - p->rect[tnr][0][0]; - h = p->rect[tnr][1][1] - p->rect[tnr][0][1]; - if (gkss->clip_region == GKS_K_REGION_ELLIPSE) + cairo_save(p->cr); + cairo_translate(p->cr, x + 0.5 * w, y + 0.5 * h); + cairo_scale(p->cr, 1., h / w); + if (gkss->clip_start_angle > 0 || gkss->clip_end_angle < 360) { - cairo_save(p->cr); - cairo_translate(p->cr, x + 0.5 * w, y + 0.5 * h); - cairo_scale(p->cr, 1., h / w); - cairo_arc(p->cr, 0., 0., w * 0.5, 0, 2 * M_PI); - cairo_restore(p->cr); + cairo_move_to(p->cr, 0, 0); + cairo_arc_negative(p->cr, 0, 0, w * 0.5, -gkss->clip_start_angle * M_PI / 180, + -gkss->clip_end_angle * M_PI / 180); } else { - cairo_rectangle(p->cr, x, y, w, h); + cairo_arc(p->cr, 0., 0., w * 0.5, 0, 2 * M_PI); } - cairo_clip(p->cr); + cairo_restore(p->cr); + } + else + { + cairo_rectangle(p->cr, x, y, w, h); } + cairo_clip(p->cr); } static void set_clipping(int index) diff --git a/lib/gks/plugin/gsplugin.c b/lib/gks/plugin/gsplugin.c index c29108718..28916e769 100644 --- a/lib/gks/plugin/gsplugin.c +++ b/lib/gks/plugin/gsplugin.c @@ -852,14 +852,16 @@ static void set_clip(double *clrt) if (gkss->clip_region == GKS_K_REGION_ELLIPSE && (gkss->clip_tnr != 0 || gkss->clip == GKS_K_CLIP)) { - int x, y, rx, ry; + double x, y, rx, ry; - x = (int)(0.5 * (cx1 + cx2) + 0.5); - y = (int)(0.5 * (cy1 + cy2) + 0.5); - rx = (int)(0.5 * (cx2 - cx1) + 1); - ry = (int)(0.5 * (cy2 - cy1) + 1); + x = 0.5 * (cx1 + cx2); + y = 0.5 * (cy1 + cy2); + rx = 0.5 * (cx2 - cx1); + ry = 0.5 * (cy2 - cy1); - snprintf(buffer, 120, "np %d %d %d %d 0 360 ellipse clip", x, y, rx, ry); + snprintf(buffer, 120, "np %.2f %.2f m %.2f %.2f l %.2f %.2f %.2f %.2f %.2f %.2f ellipse clip", x, y, + x + rx * cos(gkss->clip_start_angle * M_PI / 180), y + ry * sin(gkss->clip_start_angle * M_PI / 180), x, + y, rx, ry, gkss->clip_start_angle, gkss->clip_end_angle); } else { diff --git a/lib/gks/plugin/pgfplugin.c b/lib/gks/plugin/pgfplugin.c index 3ecab50ac..d49b730f8 100644 --- a/lib/gks/plugin/pgfplugin.c +++ b/lib/gks/plugin/pgfplugin.c @@ -921,10 +921,18 @@ static void set_clip_rect(int tnr) y = (p->rect[tnr][0][1] + p->rect[tnr][1][1]) / 2; w = p->rect[tnr][1][0] - p->rect[tnr][0][0]; h = p->rect[tnr][1][1] - p->rect[tnr][0][1]; - pgf_printf(p->stream, - "\\begin{scope}\n" - "\\clip (%f,%f) ellipse (%f and %f);\n", - x, y, w / 2, h / 2); + if (gkss->clip_start_angle > 0 || gkss->clip_end_angle < 360) + pgf_printf(p->stream, + "\\begin{scope}\n" + "\\clip (%f,%f) arc (%f:%f:%f and %f) -- (%f,%f);\n", + x + 0.5 * w * cos(-gkss->clip_start_angle * M_PI / 180), + y + 0.5 * h * sin(-gkss->clip_start_angle * M_PI / 180), -gkss->clip_start_angle, + -gkss->clip_end_angle, w / 2, h / 2, x, y); + else + pgf_printf(p->stream, + "\\begin{scope}\n" + "\\clip (%f,%f) ellipse (%f and %f);\n", + x, y, w / 2, h / 2); } else { diff --git a/lib/gks/plugin/qtplugin_impl.cxx b/lib/gks/plugin/qtplugin_impl.cxx index d45d6b6cf..1182be0d2 100644 --- a/lib/gks/plugin/qtplugin_impl.cxx +++ b/lib/gks/plugin/qtplugin_impl.cxx @@ -304,23 +304,26 @@ static void seg_xform_rel(double *x, double *y) static void set_clip_rect(int tnr) { - if (gkss->clip_region == GKS_K_REGION_ELLIPSE) + if (gkss->clip_tnr != 0) + tnr = gkss->clip_tnr; + else if (gkss->clip == GKS_K_NOCLIP) + tnr = 0; + + if (gkss->clip_region == GKS_K_REGION_ELLIPSE && tnr != 0) { - if (gkss->clip_tnr != 0) - p->painter->setClipRegion(QRegion(p->rect[gkss->clip_tnr].toRect(), QRegion::Ellipse)); - else if (gkss->clip == GKS_K_CLIP) - p->painter->setClipRegion(QRegion(p->rect[tnr].toRect(), QRegion::Ellipse)); + if (gkss->clip_start_angle > 0 || gkss->clip_end_angle < 360) + { + QPainterPath path; + path.moveTo(p->rect[tnr].center()); + path.arcTo(p->rect[tnr].toRect(), gkss->clip_start_angle, gkss->clip_end_angle - gkss->clip_start_angle); + p->painter->setClipPath(path); + } else - p->painter->setClipRect(p->rect[0]); + p->painter->setClipRegion(QRegion(p->rect[tnr].toRect(), QRegion::Ellipse)); } else { - if (gkss->clip_tnr != 0) - p->painter->setClipRect(p->rect[gkss->clip_tnr]); - else if (gkss->clip == GKS_K_CLIP) - p->painter->setClipRect(p->rect[tnr]); - else - p->painter->setClipRect(p->rect[0]); + p->painter->setClipRect(p->rect[tnr]); } } diff --git a/lib/gks/plugin/svgplugin.c b/lib/gks/plugin/svgplugin.c index 7a373444a..d05036702 100644 --- a/lib/gks/plugin/svgplugin.c +++ b/lib/gks/plugin/svgplugin.c @@ -1468,6 +1468,24 @@ static void gdp(int n, double *px, double *py, int primid, int nc, int *codes) } } +static void svg_arc_path(double x, double y, double rx, double ry, double start_angle, double end_angle) +{ + double a1, a2; + double start_x, start_y, end_x, end_y; + int sweep_flag; + + a1 = -start_angle * M_PI / 180; + a2 = -end_angle * M_PI / 180; + start_x = x + rx * cos(a2); + start_y = y + ry * sin(a2); + end_x = x + rx * cos(a1); + end_y = y + ry * sin(a1); + sweep_flag = end_angle - start_angle <= 180 ? 0 : 1; + + svg_printf(p->stream, "", x, y, start_x, start_y, rx, ry, + sweep_flag, end_x, end_y); +} + static void set_clip_path(int tnr) { double *vp; @@ -1517,11 +1535,21 @@ static void set_clip_path(int tnr) p->cr[p->clip_index].region = gkss->clip_region; p->rect_index = p->clip_index; if (gkss->clip_region == GKS_K_REGION_ELLIPSE && (gkss->clip_tnr != 0 || gkss->clip == GKS_K_CLIP)) - svg_printf(p->stream, - "\n \n \n \n\n", - path_id, p->rect_index, x + width / 2, y + height / 2, width / 2, height / 2); + { + if (gkss->clip_start_angle > 0 || gkss->clip_end_angle < 360) + { + svg_printf(p->stream, "\n \n", path_id, p->rect_index); + svg_arc_path(x + width / 2, y + height / 2, width / 2, height / 2, gkss->clip_start_angle, + gkss->clip_end_angle); + svg_printf(p->stream, " \n\n"); + } + else + svg_printf(p->stream, + "\n \n \n" + " \n\n", + path_id, p->rect_index, x + width / 2, y + height / 2, width / 2, height / 2); + } else svg_printf(p->stream, "\n \n clip_region == GKS_K_REGION_ELLIPSE && (gkss->clip_tnr != 0 || gkss->clip == GKS_K_CLIP)) { - int x, y, rx, ry; + double x, y, rx, ry; - x = (int)(0.5 * (cx1 + cx2) + 0.5); - y = (int)(0.5 * (cy1 + cy2) + 0.5); - rx = (int)(0.5 * (cx2 - cx1) + 1); - ry = (int)(0.5 * (cy2 - cy1) + 1); + x = 0.5 * (cx1 + cx2); + y = 0.5 * (cy1 + cy2); + rx = 0.5 * (cx2 - cx1); + ry = 0.5 * (cy2 - cy1); - snprintf(buffer, 120, "np %d %d %d %d 0 360 ellipse clip", x, y, rx, ry); + snprintf(buffer, 120, "np %.2f %.2f m %.2f %.2f l %.2f %.2f %.2f %.2f %.2f %.2f ellipse clip", x, y, + x + rx * cos(gkss->clip_start_angle * M_PI / 180), y + ry * sin(gkss->clip_start_angle * M_PI / 180), x, + y, rx, ry, gkss->clip_start_angle, gkss->clip_end_angle); } else { diff --git a/lib/gks/quartz/GKSView.m b/lib/gks/quartz/GKSView.m index 41fef59e8..36b097576 100644 --- a/lib/gks/quartz/GKSView.m +++ b/lib/gks/quartz/GKSView.m @@ -345,7 +345,8 @@ - (void)interp:(char *)str RESOLVE(f_arr_1, double, sizeof(double)); break; - case 32: /* set character up vector */ + case 32: /* set character up vector */ + case 212: /* set clip sector */ RESOLVE(f_arr_1, double, sizeof(double)); RESOLVE(f_arr_2, double, sizeof(double)); break; @@ -637,6 +638,11 @@ - (void)interp:(char *)str case 211: gkss->clip_region = i_arr[0]; break; + + case 212: + gkss->clip_start_angle = f_arr_1[0]; + gkss->clip_end_angle = f_arr_2[0]; + break; } RESOLVE(len, int, sizeof(int)); @@ -1133,8 +1139,33 @@ static void begin_context(CGContextRef context) if (gkss->clip_region == GKS_K_REGION_ELLIPSE && (gkss->clip_tnr != 0 || gkss->clip == GKS_K_CLIP)) { CGMutablePathRef path = CGPathCreateMutable(); - CGPathAddEllipseInRect(path, NULL, clipRect); - CGContextAddPath(context, path); + if (gkss->clip_start_angle > 0 || gkss->clip_end_angle < 360) + { + double a1, a2, x, y, start_x, start_y, end_x, end_y, w, h; + + a1 = gkss->clip_start_angle * M_PI / 180; + a2 = gkss->clip_end_angle * M_PI / 180; + w = clipRect.size.width; + h = clipRect.size.height; + x = clipRect.origin.x + w * 0.5; + y = clipRect.origin.y + h * 0.5; + start_x = x + w * cos(a1); + start_y = y + h * sin(a1); + end_x = x + w * cos(a2); + end_y = y + h * sin(a2); + + CGAffineTransform m = CGAffineTransformMakeTranslation(x, y); + m = CGAffineTransformConcat(CGAffineTransformMakeScale(1.0, h / w), m); + CGPathAddArc(path, &m, 0, 0, 0.5 * w, a1, a2, a1 > a2); + CGPathAddLineToPoint(path, &m, 0, 0); + CGContextAddPath(context, path); + CGContextClosePath(context); + } + else + { + CGPathAddEllipseInRect(path, NULL, clipRect); + CGContextAddPath(context, path); + } CGContextClip(context); CGPathRelease(path); } diff --git a/lib/gr/gr.c b/lib/gr/gr.c index ea4e8f13e..c6def61f8 100644 --- a/lib/gr/gr.c +++ b/lib/gr/gr.c @@ -172,14 +172,16 @@ typedef struct int ints; int styli; int facoli; + int clip; int tnr; double wn[4], vp[4]; int scale_options; double bwidth; int bcoli; int clip_tnr; - int resize_behaviour; int clip_region; + double clip_start_angle, clip_end_angle; + int resize_behaviour; double alpha; double txoff[2]; } state_list; @@ -5577,9 +5579,9 @@ static void draw_axis(char which, axis_t *axis, int pass) void gr_drawaxis(char which, axis_t *axis) { - int errind, tnr, ltype, clsw, halign, valign; + int errind, tnr, ltype, clsw; double wn[4], vp[4], clrt[4]; - int i, pass; + int pass; check_autoinit; @@ -5610,7 +5612,7 @@ void gr_drawaxis(char which, axis_t *axis) static void draw_axis_grid(char which, axis_t *axis, int pass) { int errind, tnr, color; - double wn[4], vp[4], width; + double wn[4], vp[4], width, alpha; int i; /* inquire current normalization transformation */ @@ -5618,10 +5620,11 @@ static void draw_axis_grid(char which, axis_t *axis, int pass) gks_inq_current_xformno(&errind, &tnr); gks_inq_xform(tnr, &errind, wn, vp); - /* save line width and line color */ + /* save line width, line color and transparency */ gks_inq_pline_linewidth(&errind, &width); gks_inq_pline_color_index(&errind, &color); + gks_inq_transparency(&errind, &alpha); gks_inq_pline_color_index(&errind, &color); @@ -5629,10 +5632,10 @@ static void draw_axis_grid(char which, axis_t *axis, int pass) { if (axis->ticks[i].is_major == pass) { - if (color != 0) - gks_set_pline_color_index(axis->ticks[i].is_major ? 88 : 90); + if (color != 1) + gks_set_transparency(axis->ticks[i].is_major ? alpha * 0.4 : alpha * 0.2); else - gks_set_pline_linewidth(axis->ticks[i].is_major ? 2.0 : 1.0); + gks_set_pline_color_index(axis->ticks[i].is_major ? 88 : 90); if (which == 'X') { @@ -5649,17 +5652,17 @@ static void draw_axis_grid(char which, axis_t *axis, int pass) } } - /* restore line width and line color */ + /* restore line width, line color and transparency */ gks_set_pline_linewidth(width); gks_set_pline_color_index(color); + gks_set_transparency(alpha); } void gr_drawaxes(axis_t *x_axis, axis_t *y_axis, int options) { int errind, tnr, ltype, clsw; double wn[4], vp[4], clrt[4]; - double tick, minor_tick, major_tick; int pass; axis_t axis; @@ -5752,12 +5755,12 @@ void gr_freeaxis(axis_t *axis) } } -static void grid_line(double x0, double y0, double x1, double y1, int color, int major) +static void grid_line(double x0, double y0, double x1, double y1, int color, double alpha, int major) { - if (color != 0) - gks_set_pline_color_index(major ? 88 : 90); + if (color != 1) + gks_set_transparency(major ? alpha * 0.4 : alpha * 0.2); else - gks_set_pline_linewidth(major ? 2.0 : 1.0); + gks_set_pline_color_index(major ? 88 : 90); start_pline(x0, y0); pline(x1, y1); @@ -5791,7 +5794,7 @@ void gr_grid(double x_tick, double y_tick, double x_org, double y_org, int major { int errind, tnr; int ltype, color, clsw, major; - double width; + double width, alpha; double clrt[4], wn[4], vp[4]; double x_min, x_max, y_min, y_max, feps; @@ -5818,11 +5821,12 @@ void gr_grid(double x_tick, double y_tick, double x_org, double y_org, int major y_min = wn[2]; y_max = wn[3]; - /* save linetype, line width, line color and clipping indicator */ + /* save linetype, line width, line color, transparency and clipping indicator */ gks_inq_pline_linetype(&errind, <ype); gks_inq_pline_linewidth(&errind, &width); gks_inq_pline_color_index(&errind, &color); + gks_inq_transparency(&errind, &alpha); gks_inq_clip(&errind, &clsw, clrt); gks_set_pline_linetype(GKS_K_LINETYPE_SOLID); @@ -5848,7 +5852,7 @@ void gr_grid(double x_tick, double y_tick, double x_org, double y_org, int major major = i == 0 ? 1 : 0; if (yi != y_min) { - if (pass == major) grid_line(x_min, yi, x_max, yi, color, major); + if (pass == major) grid_line(x_min, yi, x_max, yi, color, alpha, major); } } @@ -5881,7 +5885,7 @@ void gr_grid(double x_tick, double y_tick, double x_org, double y_org, int major else major = 0; - if (pass == major) grid_line(x_min, yi, x_max, yi, color, major); + if (pass == major) grid_line(x_min, yi, x_max, yi, color, alpha, major); i++; yi = y_org + i * y_tick; @@ -5907,7 +5911,7 @@ void gr_grid(double x_tick, double y_tick, double x_org, double y_org, int major major = i == 0 ? 1 : 0; if (xi != x_min) { - if (pass == major) grid_line(xi, y_min, xi, y_max, color, major); + if (pass == major) grid_line(xi, y_min, xi, y_max, color, alpha, major); } } @@ -5940,7 +5944,7 @@ void gr_grid(double x_tick, double y_tick, double x_org, double y_org, int major else major = 0; - if (pass == major) grid_line(xi, y_min, xi, y_max, color, major); + if (pass == major) grid_line(xi, y_min, xi, y_max, color, alpha, major); i++; xi = x_org + i * x_tick; @@ -5949,11 +5953,12 @@ void gr_grid(double x_tick, double y_tick, double x_org, double y_org, int major } } - /* restore linetype, line width, line color and clipping indicator */ + /* restore linetype, line width, line color, transparency and clipping indicator */ gks_set_pline_linetype(ltype); gks_set_pline_linewidth(width); gks_set_pline_color_index(color); + gks_set_transparency(alpha); gks_set_clipping(clsw); if (flag_stream) @@ -5962,12 +5967,13 @@ void gr_grid(double x_tick, double y_tick, double x_org, double y_org, int major x_tick, y_tick, x_org, y_org, major_x, major_y); } -static void grid_line3d(double x0, double y0, double z0, double x1, double y1, double z1, int color, int major) +static void grid_line3d(double x0, double y0, double z0, double x1, double y1, double z1, int color, double alpha, + int major) { - if (color != 0) - gks_set_pline_color_index(major ? 88 : 90); + if (color != 1) + gks_set_transparency(major ? alpha * 0.4 : alpha * 0.2); else - gks_set_pline_linewidth(major ? 2.0 : 1.0); + gks_set_pline_color_index(major ? 88 : 90); start_pline3d(x0, y0, z0); pline3d(x1, y1, z1); @@ -6012,7 +6018,7 @@ void gr_grid3d(double x_tick, double y_tick, double z_tick, double x_org, double int modern_projection_type; int ltype, color, clsw, major; - double width; + double width, alpha; double x_min = 0, x_max = 0, y_min = 0, y_max = 0, z_min = 0, z_max = 0; @@ -6064,11 +6070,12 @@ void gr_grid3d(double x_tick, double y_tick, double z_tick, double x_org, double z_max = wx.zmax; } - /* save linetype, line width, line color and clipping indicator */ + /* save linetype, line width, line color, transparency and clipping indicator */ gks_inq_pline_linetype(&errind, <ype); gks_inq_pline_linewidth(&errind, &width); gks_inq_pline_color_index(&errind, &color); + gks_inq_transparency(&errind, &alpha); gks_inq_clip(&errind, &clsw, clrt); gks_set_pline_linetype(GKS_K_LINETYPE_SOLID); @@ -6092,8 +6099,8 @@ void gr_grid3d(double x_tick, double y_tick, double z_tick, double x_org, double major = i == 0; if (fabs(zi - z_min) > FEPS * zi) { - grid_line3d(x_org, y_min, zi, x_org, y_max, zi, color, major); - grid_line3d(x_min, y_org, zi, x_max, y_org, zi, color, major); + grid_line3d(x_org, y_min, zi, x_org, y_max, zi, color, alpha, major); + grid_line3d(x_min, y_org, zi, x_max, y_org, zi, color, alpha, major); } } @@ -6127,8 +6134,8 @@ void gr_grid3d(double x_tick, double y_tick, double z_tick, double x_org, double if (fabs(zi - z_min) > FEPS * zi) { - grid_line3d(x_org, y_min, zi, x_org, y_max, zi, color, major); - grid_line3d(x_min, y_org, zi, x_max, y_org, zi, color, major); + grid_line3d(x_org, y_min, zi, x_org, y_max, zi, color, alpha, major); + grid_line3d(x_min, y_org, zi, x_max, y_org, zi, color, alpha, major); } i++; @@ -6155,8 +6162,8 @@ void gr_grid3d(double x_tick, double y_tick, double z_tick, double x_org, double major = i == 0; if (fabs(yi - y_min) > FEPS * yi) { - grid_line3d(x_min, yi, z_org, x_max, yi, z_org, color, major); - grid_line3d(x_org, yi, z_min, x_org, yi, z_max, color, major); + grid_line3d(x_min, yi, z_org, x_max, yi, z_org, color, alpha, major); + grid_line3d(x_org, yi, z_min, x_org, yi, z_max, color, alpha, major); } } @@ -6190,8 +6197,8 @@ void gr_grid3d(double x_tick, double y_tick, double z_tick, double x_org, double if (fabs(yi - y_min) > FEPS * yi) { - grid_line3d(x_min, yi, z_org, x_max, yi, z_org, color, major); - grid_line3d(x_org, yi, z_min, x_org, yi, z_max, color, major); + grid_line3d(x_min, yi, z_org, x_max, yi, z_org, color, alpha, major); + grid_line3d(x_org, yi, z_min, x_org, yi, z_max, color, alpha, major); } i++; @@ -6218,8 +6225,8 @@ void gr_grid3d(double x_tick, double y_tick, double z_tick, double x_org, double major = i == 0; if (fabs(xi - x_min) > FEPS * xi) { - grid_line3d(xi, y_min, z_org, xi, y_max, z_org, color, major); - grid_line3d(xi, y_org, z_min, xi, y_org, z_max, color, major); + grid_line3d(xi, y_min, z_org, xi, y_max, z_org, color, alpha, major); + grid_line3d(xi, y_org, z_min, xi, y_org, z_max, color, alpha, major); } } @@ -6253,8 +6260,8 @@ void gr_grid3d(double x_tick, double y_tick, double z_tick, double x_org, double if (fabs(xi - x_min) > FEPS * xi) { - grid_line3d(xi, y_min, z_org, xi, y_max, z_org, color, major); - grid_line3d(xi, y_org, z_min, xi, y_org, z_max, color, major); + grid_line3d(xi, y_min, z_org, xi, y_max, z_org, color, alpha, major); + grid_line3d(xi, y_org, z_min, xi, y_org, z_max, color, alpha, major); } i++; @@ -6263,11 +6270,12 @@ void gr_grid3d(double x_tick, double y_tick, double z_tick, double x_org, double } } - /* restore linetype, line width, line color and clipping indicator */ + /* restore linetype, line width, line color, transparency and clipping indicator */ gks_set_pline_linetype(ltype); gks_set_pline_linewidth(width); gks_set_pline_color_index(color); + gks_set_transparency(alpha); gks_set_clipping(clsw); if (flag_stream) @@ -9302,7 +9310,7 @@ void gr_surface(int nx, int ny, double *px, double *py, double *pz, int option) gks_set_fill_color_index(color); } - gks_select_xform(MODERN_NDC); + if (modern_projection_type) gks_select_xform(MODERN_NDC); np = 4; gks_fillarea(np, xn, yn); @@ -9313,7 +9321,7 @@ void gr_surface(int nx, int ny, double *px, double *py, double *pz, int option) gks_polyline(np, xn, yn); } - gks_select_xform(tnr); + if (modern_projection_type) gks_select_xform(tnr); } j--; @@ -9830,7 +9838,7 @@ static void rebin(int nx, int ny, double *px, double *py, double *pz, int *nxq, void gr_contour(int nx, int ny, int nh, double *px, double *py, double *h, double *pz, int major_h) { int i, j; - int errind, tnr, ltype, color, halign, valign; + int errind, ltype, color, halign, valign; double chux, chuy; int nxq, nyq; double *xq = NULL, *yq = NULL, *zq = NULL; @@ -12030,7 +12038,7 @@ static void latex2image(char *string, int pointSize, double *rgb, int *width, in rename(png, path); if (remove(tex) != 0 || remove(dvi) != 0) { - fprintf(stderr, "error deleting temprorary files\n"); + fprintf(stderr, "error deleting temporary files\n"); } } else @@ -12947,6 +12955,7 @@ void gr_savestate(void) { int errind; state_list *s = NULL; + double clrt[4]; check_autoinit; @@ -12976,6 +12985,7 @@ void gr_savestate(void) gks_inq_fill_color_index(&errind, &s->facoli); gks_inq_transparency(&errind, &s->alpha); + gks_inq_clip(&errind, &s->clip, clrt); gks_inq_current_xformno(&errind, &s->tnr); gks_inq_xform(WC, &errind, s->wn, s->vp); @@ -12984,8 +12994,9 @@ void gr_savestate(void) gks_inq_border_width(&errind, &s->bwidth); gks_inq_border_color_index(&errind, &s->bcoli); gks_inq_clip_xform(&errind, &s->clip_tnr); - gks_inq_resize_behaviour(&s->resize_behaviour); gks_inq_clip_region(&errind, &s->clip_region); + gks_inq_clip_sector(&errind, &s->clip_start_angle, &s->clip_end_angle); + gks_inq_resize_behaviour(&s->resize_behaviour); s->txoff[0] = txoff[0]; s->txoff[1] = txoff[1]; @@ -13026,6 +13037,7 @@ void gr_restorestate(void) gks_set_fill_color_index(s->facoli); gks_set_transparency(s->alpha); + gks_set_clipping(s->clip); gks_select_xform(s->tnr); gks_set_window(WC, s->wn[0], s->wn[1], s->wn[2], s->wn[3]); gks_set_window(MODERN_NDC, -1, 1, -1, 1); @@ -13041,8 +13053,9 @@ void gr_restorestate(void) gks_set_border_width(s->bwidth); gks_set_border_color_index(s->bcoli); gks_select_clip_xform(s->clip_tnr); - gks_set_resize_behaviour(s->resize_behaviour); gks_set_clip_region(s->clip_region); + gks_set_clip_sector(s->clip_start_angle, s->clip_end_angle); + gks_set_resize_behaviour(s->resize_behaviour); s->txoff[0] = txoff[0]; s->txoff[1] = txoff[1]; @@ -13070,6 +13083,7 @@ void gr_restorestate(void) ctx->styli = s->styli; ctx->facoli = s->facoli; + ctx->clip = s->clip; ctx->tnr = s->tnr; ctx->wn[0] = s->wn[0]; ctx->wn[2] = s->wn[2]; @@ -13085,8 +13099,10 @@ void gr_restorestate(void) ctx->bwidth = s->bwidth; ctx->bcoli = s->bcoli; ctx->clip_tnr = s->clip_tnr; - ctx->resize_behaviour = s->resize_behaviour; ctx->clip_region = s->clip_region; + ctx->clip_start_angle = s->clip_start_angle; + ctx->clip_end_angle = s->clip_end_angle; + ctx->resize_behaviour = s->resize_behaviour; ctx->txoff[0] = s->txoff[0]; ctx->txoff[1] = s->txoff[1]; @@ -13157,6 +13173,7 @@ void gr_selectcontext(int context) ctx->facoli = 1; ctx->alpha = 1.0; + ctx->clip = GKS_K_NOCLIP; ctx->tnr = WC; ctx->wn[0] = ctx->wn[2] = 0; ctx->wn[1] = ctx->wn[3] = 1; @@ -13168,8 +13185,10 @@ void gr_selectcontext(int context) ctx->bwidth = 1; ctx->bcoli = 1; ctx->clip_tnr = 0; - ctx->resize_behaviour = GKS_K_RESIZE; ctx->clip_region = GKS_K_REGION_RECTANGLE; + ctx->clip_start_angle = 0; + ctx->clip_end_angle = 360; + ctx->resize_behaviour = GKS_K_RESIZE; ctx->txoff[0] = 0; ctx->txoff[1] = 0; @@ -13198,6 +13217,7 @@ void gr_selectcontext(int context) gks_set_fill_color_index(ctx->facoli); gks_set_transparency(ctx->alpha); + gks_set_clipping(ctx->clip); gks_select_xform(ctx->tnr); gks_set_window(WC, ctx->wn[0], ctx->wn[1], ctx->wn[2], ctx->wn[3]); gks_set_window(MODERN_NDC, -1, 1, -1, 1); @@ -13213,8 +13233,9 @@ void gr_selectcontext(int context) gks_set_border_width(ctx->bwidth); gks_set_border_color_index(ctx->bcoli); gks_select_clip_xform(ctx->clip_tnr); - gks_set_resize_behaviour(ctx->resize_behaviour); gks_set_clip_region(ctx->clip_region); + gks_set_clip_sector(ctx->clip_start_angle, ctx->clip_end_angle); + gks_set_resize_behaviour(ctx->resize_behaviour); txoff[0] = ctx->txoff[0]; txoff[1] = ctx->txoff[1]; @@ -13230,6 +13251,7 @@ void gr_savecontext(int context) { int errind; int id; + double clrt[4]; check_autoinit; @@ -13283,6 +13305,7 @@ void gr_savecontext(int context) gks_inq_fill_color_index(&errind, &app_context->buf[id]->facoli); gks_inq_transparency(&errind, &app_context->buf[id]->alpha); + gks_inq_clip(&errind, &app_context->buf[id]->clip, clrt); gks_inq_current_xformno(&errind, &app_context->buf[id]->tnr); gks_inq_xform(WC, &errind, app_context->buf[id]->wn, app_context->buf[id]->vp); @@ -13291,8 +13314,9 @@ void gr_savecontext(int context) gks_inq_border_width(&errind, &app_context->buf[id]->bwidth); gks_inq_border_color_index(&errind, &app_context->buf[id]->bcoli); gks_inq_clip_xform(&errind, &app_context->buf[id]->clip_tnr); - gks_inq_resize_behaviour(&app_context->buf[id]->resize_behaviour); gks_inq_clip_region(&errind, &app_context->buf[id]->clip_region); + gks_inq_clip_sector(&errind, &app_context->buf[id]->clip_start_angle, &app_context->buf[id]->clip_end_angle); + gks_inq_resize_behaviour(&app_context->buf[id]->resize_behaviour); app_context->buf[id]->txoff[0] = txoff[0]; app_context->buf[id]->txoff[1] = txoff[1]; @@ -13307,6 +13331,7 @@ void gr_destroycontext(int context) { int errind; int id; + double clrt[4]; check_autoinit; @@ -13360,6 +13385,7 @@ void gr_destroycontext(int context) gks_inq_fill_color_index(&errind, &app_context->buf[id]->facoli); gks_inq_transparency(&errind, &app_context->buf[id]->alpha); + gks_inq_clip(&errind, &app_context->buf[id]->clip, clrt); gks_inq_current_xformno(&errind, &app_context->buf[id]->tnr); gks_inq_xform(WC, &errind, app_context->buf[id]->wn, app_context->buf[id]->vp); @@ -13368,8 +13394,9 @@ void gr_destroycontext(int context) gks_inq_border_width(&errind, &app_context->buf[id]->bwidth); gks_inq_border_color_index(&errind, &app_context->buf[id]->bcoli); gks_inq_clip_xform(&errind, &app_context->buf[id]->clip_tnr); - gks_inq_resize_behaviour(&app_context->buf[id]->resize_behaviour); gks_inq_clip_region(&errind, &app_context->buf[id]->clip_region); + gks_inq_clip_sector(&errind, &app_context->buf[id]->clip_start_angle, &app_context->buf[id]->clip_end_angle); + gks_inq_resize_behaviour(&app_context->buf[id]->resize_behaviour); app_context->buf[id]->txoff[0] = txoff[0]; app_context->buf[id]->txoff[1] = txoff[1]; @@ -14566,6 +14593,29 @@ void gr_inqclipregion(int *region) gks_inq_clip_region(&errind, region); } +void gr_setclipsector(double start_angle, double end_angle) +{ + check_autoinit; + + gks_set_clip_sector(start_angle, end_angle); + if (ctx) + { + ctx->clip_start_angle = start_angle; + ctx->clip_end_angle = end_angle; + } + + if (flag_stream) gr_writestream("\n", start_angle, end_angle); +} + +void gr_inqclipsector(double *start_angle, double *end_angle) +{ + int errind; + + check_autoinit; + + gks_inq_clip_sector(&errind, start_angle, end_angle); +} + void gr_settextoffset(double xoff, double yoff) { check_autoinit; diff --git a/lib/gr/gr.h b/lib/gr/gr.h index a435d6ff2..fa64a62c8 100644 --- a/lib/gr/gr.h +++ b/lib/gr/gr.h @@ -67,14 +67,14 @@ typedef enum GR_OPTION_Z_LOG2 = 1u << 8u, GR_OPTION_X_LN = 1u << 9u, GR_OPTION_Y_LN = 1u << 10u, - GR_OPTION_Z_LN = 1u << 11u, + GR_OPTION_Z_LN = 1u << 11u } scale_option_t; typedef enum { GR_SPEC_LINE = 1u << 0u, GR_SPEC_MARKER = 1u << 1u, - GR_SPEC_COLOR = 1u << 2u, + GR_SPEC_COLOR = 1u << 2u } linespec_t; typedef enum @@ -86,7 +86,7 @@ typedef enum GR_OPTION_COLORED_MESH, GR_OPTION_CELL_ARRAY, GR_OPTION_SHADED_MESH, - GR_OPTION_3D_MESH, /* for GR3 */ + GR_OPTION_3D_MESH /* for GR3 */ } surface_option_t; typedef enum @@ -102,7 +102,7 @@ typedef enum GR_LINETO, GR_CURVE3, GR_CURVE4, - GR_CLOSEPOLY = 0x4f, + GR_CLOSEPOLY = 0x4f } path_code_t; typedef enum @@ -112,7 +112,7 @@ typedef enum GR_XFORM_LOG, GR_XFORM_LOGLOG, GR_XFORM_CUBIC, - GR_XFORM_EQUALIZED, + GR_XFORM_EQUALIZED } xform_types_t; typedef enum @@ -120,7 +120,7 @@ typedef enum GR_INTERP2_NEAREST, GR_INTERP2_LINEAR, GR_INTERP2_SPLINE, - GR_INTERP2_CUBIC, + GR_INTERP2_CUBIC } interp2_method_t; typedef struct @@ -446,6 +446,8 @@ DLLEXPORT void gr_setmathfont(int font); DLLEXPORT void gr_inqmathfont(int *font); DLLEXPORT void gr_setclipregion(int region); DLLEXPORT void gr_inqclipregion(int *region); +DLLEXPORT void gr_setclipsector(double start_angle, double end_angle); +DLLEXPORT void gr_inqclipsector(double *start_angle, double *end_angle); DLLEXPORT void gr_settextoffset(double xoff, double yoff); DLLEXPORT char *gr_ftoa(char *string, double value, format_reference_t *reference); DLLEXPORT void gr_getformat(format_reference_t *result, double origin, double min, double max, double tick_width, diff --git a/lib/gr/import.c b/lib/gr/import.c index 6e818e806..dc16ac245 100644 --- a/lib/gr/import.c +++ b/lib/gr/import.c @@ -68,6 +68,7 @@ static char *format[] = { "setcharup:ff", "setclip:i", "setclipregion:i", + "setclipsector:ff", "setcolormap:i", "setcolorrep:ifff", "setfillcolorind:i", @@ -443,154 +444,157 @@ static void gr(int id) gr_setclipregion(i_arg[0]); break; case 48: - gr_setcolormap(i_arg[0]); + gr_setclipsector(f_arg[0], f_arg[1]); break; case 49: - gr_setcolorrep(i_arg[0], f_arg[0], f_arg[1], f_arg[2]); + gr_setcolormap(i_arg[0]); break; case 50: - gr_setfillcolorind(i_arg[0]); + gr_setcolorrep(i_arg[0], f_arg[0], f_arg[1], f_arg[2]); break; case 51: - gr_setfillintstyle(i_arg[0]); + gr_setfillcolorind(i_arg[0]); break; case 52: - gr_setfillstyle(i_arg[0]); + gr_setfillintstyle(i_arg[0]); break; case 53: - gr_setlinecolorind(i_arg[0]); + gr_setfillstyle(i_arg[0]); break; case 54: - gr_setlinetype(i_arg[0]); + gr_setlinecolorind(i_arg[0]); break; case 55: - gr_setlinewidth(f_arg[0]); + gr_setlinetype(i_arg[0]); break; case 56: - gr_setmarkercolorind(i_arg[0]); + gr_setlinewidth(f_arg[0]); break; case 57: - gr_setmarkersize(f_arg[0]); + gr_setmarkercolorind(i_arg[0]); break; case 58: - gr_setmarkertype(i_arg[0]); + gr_setmarkersize(f_arg[0]); break; case 59: - gr_setmathfont(i_arg[0]); + gr_setmarkertype(i_arg[0]); break; case 60: - gr_setorthographicprojection(f_arg[0], f_arg[1], f_arg[2], f_arg[3], f_arg[4], f_arg[5]); + gr_setmathfont(i_arg[0]); break; case 61: - gr_setperspectiveprojection(f_arg[0], f_arg[1], f_arg[2]); + gr_setorthographicprojection(f_arg[0], f_arg[1], f_arg[2], f_arg[3], f_arg[4], f_arg[5]); break; case 62: - gr_setpicturesizeforvolume(i_arg[0], i_arg[1]); + gr_setperspectiveprojection(f_arg[0], f_arg[1], f_arg[2]); break; case 63: - gr_setprojectiontype(i_arg[0]); + gr_setpicturesizeforvolume(i_arg[0], i_arg[1]); break; case 64: - gr_setresizebehaviour(i_arg[0]); + gr_setprojectiontype(i_arg[0]); break; case 65: - gr_setscale(i_arg[0]); + gr_setresizebehaviour(i_arg[0]); break; case 66: - gr_setscalefactors3d(f_arg[0], f_arg[1], f_arg[2]); + gr_setscale(i_arg[0]); break; case 67: - gr_setspace(f_arg[0], f_arg[1], i_arg[0], i_arg[1]); + gr_setscalefactors3d(f_arg[0], f_arg[1], f_arg[2]); break; case 68: - gr_setspace3d(f_arg[0], f_arg[1], f_arg[2], f_arg[3]); + gr_setspace(f_arg[0], f_arg[1], i_arg[0], i_arg[1]); break; case 69: - gr_settextalign(i_arg[0], i_arg[1]); + gr_setspace3d(f_arg[0], f_arg[1], f_arg[2], f_arg[3]); break; case 70: - gr_settextcolorind(i_arg[0]); + gr_settextalign(i_arg[0], i_arg[1]); break; case 71: - gr_settextencoding(i_arg[0]); + gr_settextcolorind(i_arg[0]); break; case 72: - gr_settextfontprec(i_arg[0], i_arg[1]); + gr_settextencoding(i_arg[0]); break; case 73: - gr_settextoffset(f_arg[0], f_arg[1]); + gr_settextfontprec(i_arg[0], i_arg[1]); break; case 74: - gr_settextpath(i_arg[0]); + gr_settextoffset(f_arg[0], f_arg[1]); break; case 75: - gr_setthreadnumber(i_arg[0]); + gr_settextpath(i_arg[0]); break; case 76: - gr_settitles3d(s_arg[0], s_arg[1], s_arg[2]); + gr_setthreadnumber(i_arg[0]); break; case 77: + gr_settitles3d(s_arg[0], s_arg[1], s_arg[2]); + break; + case 78: gr_settransformationparameters(f_arg[0], f_arg[1], f_arg[2], f_arg[3], f_arg[4], f_arg[5], f_arg[6], f_arg[7], f_arg[8]); break; - case 78: + case 79: gr_settransparency(f_arg[0]); break; - case 79: + case 80: gr_setviewport(f_arg[0], f_arg[1], f_arg[2], f_arg[3]); break; - case 80: + case 81: gr_setvolumebordercalculation(i_arg[0]); break; - case 81: + case 82: gr_setwindow(f_arg[0], f_arg[1], f_arg[2], f_arg[3]); break; - case 82: + case 83: gr_setwindow3d(f_arg[0], f_arg[1], f_arg[2], f_arg[3], f_arg[4], f_arg[5]); break; - case 83: + case 84: gr_setwsviewport(f_arg[0], f_arg[1], f_arg[2], f_arg[3]); break; - case 84: + case 85: gr_setwswindow(f_arg[0], f_arg[1], f_arg[2], f_arg[3]); break; - case 85: + case 86: gr_shadelines(i_arg[0], f_arr[0], f_arr[1], i_arg[1], i_arg[2], i_arg[3]); break; - case 86: + case 87: gr_shadepoints(i_arg[0], f_arr[0], f_arr[1], i_arg[1], i_arg[2], i_arg[3]); break; - case 87: + case 88: gr_spline(i_arg[0], f_arr[0], f_arr[1], i_arg[1], i_arg[2]); break; - case 88: + case 89: gr_surface(i_arg[0], i_arg[1], f_arr[0], f_arr[1], f_arr[2], i_arg[2]); break; - case 89: + case 90: gr_text(f_arg[0], f_arg[1], s_arg[0]); break; - case 90: + case 91: gr_textext(f_arg[0], f_arg[1], s_arg[0]); break; - case 91: + case 92: gr_textx(f_arg[0], f_arg[1], s_arg[0], i_arg[0]); break; - case 92: + case 93: gr_titles3d(s_arg[0], s_arg[1], s_arg[2]); break; - case 93: + case 94: gr_tricontour(i_arg[0], f_arr[0], f_arr[1], f_arr[2], i_arg[2], f_arr[3]); break; - case 94: + case 95: gr_trisurface(i_arg[0], f_arr[0], f_arr[1], f_arr[2]); break; - case 95: + case 96: gr_unselectcontext(); break; - case 96: + case 97: gr_uselinespec(s_arg[0]); break; - case 97: + case 98: gr_verrorbars(i_arg[0], f_arr[0], f_arr[1], f_arr[2], f_arr[3]); break; } diff --git a/lib/grm/grplot/README.md b/lib/grm/grplot/README.md index 427d79fe4..b574fb730 100644 --- a/lib/grm/grplot/README.md +++ b/lib/grm/grplot/README.md @@ -9,7 +9,7 @@ This program allows to create plots from the command line while using simple key The following parameters are key-value pairs which can be used for every plot type. - `file`: contains the data which should be displayed. If no file is referred this results in an error message. If this parameter is the first argument the `file` keyword may be omitted. More information about these files can be found under the subchapter `Data file`. A hyphen '-' in place of a file path normally means "read from standard input". Since 'grplot' does not read from standard input by default, use '-' to redirect the input. This way 'grplot' can be used in a pipe. -- `kind`: defines the plot type that should be displayed. Possible options are: `barplot`, `contour`, `contourf`, `heatmap`, `hexbin`, `hist`, `imshow`, `isosurface`, `line`, `marginal_heatmap`, `polar`, `polar_histogram`, `polar_heatmap`, `pie`, `plot3`, `scale`, `scatter`, `scatter3`, `shade`, `surface`, `stairs`, `stem`, `tricontour`, `trisurface`, `quiver`, `volume`, `wireframe`. The default plot type is `line`. +- `kind`: defines the plot type that should be displayed. Possible options are: `barplot`, `contour`, `contourf`, `heatmap`, `hexbin`, `hist`, `imshow`, `isosurface`, `line`, `marginal_heatmap`, `polar_heatmap`, `polar_histogram`, `polar_line`, `polar_scatter`, `pie`, `plot3`, `scale`, `scatter`, `scatter3`, `shade`, `surface`, `stairs`, `stem`, `tricontour`, `trisurface`, `quiver`, `volume`, `wireframe`. The default plot type is `line`. To get extra information about a specific plot type use: @@ -22,11 +22,11 @@ The following parameters are key-value pairs which can be used for every plot ty There is another parameter that can be used for all two-dimensional data sets: - `keep_aspect_ratio` or `aspect`: defines whether the aspect ratio of the initial picture is kept or not. Possible values for this parameter are 0 or 1. -- `only_quadratic_aspect_ratio`: defines whether the aspect ratio of quadratic data (x, y) is forced to be quadratic and kept this way or not. Notice this parameter will not work when the `keep_aspect_ratio` parameter has the value of 0. Possible values for this parameter are 0 or 1. +- `only_quadratic_aspect_ratio`: defines whether the aspect ratio of quadratic data (x, y) is forced to be quadratic and kept this way or not. Notice this parameter will not work if the `keep_aspect_ratio` parameter has the value of 0. Possible values for this parameter are 0 or 1. For plots where multiple columns are read there is also a parameter that allows to select columns. -- `columns`: define the columns of the file which should be respected in the plot. The default is all columns. If all columns from x to y should be drawn use `x:y`. The `y` is necessary even when all lines from `x` to the end should be drawn. To select more than 1 specific column use the `,` without whitespace as separator. +- `columns`: define the columns of the file which should be respected in the plot. The default is all columns. If all columns from x to y should be drawn use `x:y`. The `y` is necessary even if all lines from `x` to the end should be drawn. To select more than 1 specific column use the `,` without whitespace as separator. For one-dimensional data sets there are also options to define if inside the data-file there are not just y- and maybe error-values included. These parameters are similar to the previous `column` parameter and can also be used in combination with it. @@ -35,9 +35,9 @@ For one-dimensional data sets there are also options to define if inside the dat - `error_columns`: define the columns of the file which should represent the error-data. Depending on the status of the flag parameter `equal_up_and_down_error` this parameter must include either one or two columns for each y-column which should have error bars later. If this parameter is used and includes enough columns it is not needed to set `error` to enable the error bars. It can still be set to edit the resulting error bars. - `xye_file`: defines a special case of the data-file. In this case the first column represents the x-, the second the y- and the third and maybe fourth column the error-values. The parameter can only have the values 0 and 1. If this parameter has the value 1 it is not needed to set `error` to enable the error bars. It can still be set to edit the resulting error bars. -There are more key-value parameters. These parameters only effect specific plot types. For example `bar_width` only makes sense, when bars are drawn. All possible parameters are: +There are more key-value parameters. These parameters only effect specific plot types. For example `bar_width` only makes sense, if bars are drawn. All possible parameters are: -`accelerate`, `algorithm`, `bar_color`, `bar_width`, `bin_counts`, `bin_edges`, `c`, `colormap`, `draw_edges`, `edge_color`, `edge_width`, `grplot`, `int_lim`, `isovalue`, `kind`, `levels`, `line_spec`, `major_h`, `marginal_heatmap_kind`, `marker_type`, `num_bins`, `normalization`, `orientation`, `phi_flip`, `rotation`, `scatter_z`, `stairs`, `step_where`, `style`, `tilt`, `transformation`, `x_bins`, `x_colormap`, `x_flip`, `y_bins`, `y_colormap`, `y_flip`, `y_labels` +`accelerate`, `algorithm`, `bar_color`, `bar_width`, `bin_counts`, `bin_edges`, `c`, `clip_negative`, `colormap`, `draw_edges`, `edge_color`, `edge_width`, `error_bar_style`, `grplot`, `int_lim`, `isovalue`, `keep_radii_axes`, `kind`, `levels`, `line_spec`, `major_h`, `marginal_heatmap_kind`, `marker_type`, `num_bins`, `normalization`, `orientation`, `phi_flip`, `rotation`, `scatter_z`, `stairs`, `step_where`, `style`, `tilt`, `transformation`, `x_bins`, `x_colormap`, `x_flip`, `y_bins`, `y_colormap`, `y_flip`, `y_labels` All parameters are separated by a blank. Some parameters are more complex than others. These parameters represent a container inside GRM. @@ -72,7 +72,7 @@ This is an advanced example for a command line, where container parameters are s ../../../../lib/grm/grplot/data/test.dat kind:barplot ind_edge_width:2,{{indices:2},{width:5.0},{indices:1},{width:8.0}} error:{error_bar_color:4} ``` -If wanted the plot can be exported as a `pdf`, `png`, `jpeg` or `svg` file using the interactive menu. Alternatively these files can directly be created from console line when the environment variable `GKS_WSTYPE` is set. +If wanted the plot can be exported as a `pdf`, `png`, `jpeg` or `svg` file using the interactive menu. Alternatively these files can directly be created from console line if the environment variable `GKS_WSTYPE` is set. ## Test @@ -96,7 +96,7 @@ Valid keys are: 1. `title`: sets the title of the plot 2. `x_label`, `y_label`, `z_label`: set the label for the respective axis -3. `resample_method`: defines how the data is resampled when needed +3. `resample_method`: defines how the data is resampled if needed 4. `location`: defines where the legend should be drawn 5. `x_log`, `y_log`, `z_log`: defines whether the respective axis is plotted logarithmic. These options only work if the data respects the definition of the logarithmic function. 6. `x_grid`, `y_grid`, `z_grid`: defines the grid for the respective axis @@ -112,15 +112,15 @@ The next line after the header may contain the column labels. If the data does n 2. `line`, `scatter`: One or more columns are expected here. Each column will be displayed in a single plot. The values inside the columns gets therefore interpreted as y-values. In combination with the `error` parameter every 2nd (and 3rd) column gets interpreted as error-values. More information are found by the `error` parameter itself. There is also another option which allows the user to define which columns include the x-, y- and error-values. For this the parameters `x_columns`, `y_columns` and `error_columns` can be used. 3. `isosurface`, `volume`: The expected data are multiple matrices. Each matrix represents a slice inside the volume. 4. `plot3`, `scatter`, `scatter3`, `tricontour`, `trisurface`: Three columns with data are expected, representing the x-, y- and z-data. -5. `barplot`, `hist`, `stem`, `stairs`: One column is expected which represents the y-data. In combination with the `error` parameter the 2nd (and 3rd) column gets interpreted as error-values. More information are found by the `error` parameter itself. There is also another option which allows the user to define which column include the x-, y- and error-values. For this the parameters `x_columns`, `y_columns` and `error_columns` can be used. For these kinds only one column for x and y is expected. +5. `barplot`, `hist`, `stem`, `stairs`: One or more columns are expected. Each column will be displayed in a single plot. The values inside the columns gets therefore interpreted as y-values. In combination with the `error` parameter the 2nd (and 3rd) column gets interpreted as error-values. More information are found by the `error` parameter itself. There is also another option which allows the user to define which column include the x-, y- and error-values. For this the parameters `x_columns`, `y_columns` and `error_columns` can be used. 6. `pie`: The expected data are 1-4 lines. The first line represents the data which should be displayed. The next 3 rows are used to set the RGB of the pie charts. Each row stands for one RGB element. 7. `polar_histogram`: One column is expected which represents the values. -8. `polar`: The expected data are two columns containing the angles and values. -9. `polar_heatmap`: The expected data is a matrix. Each element of the matrix is displayed according to its position inside the matrix. These elements are interpreted as values in theta- and phi-direction. When not given, theta will be in the range of 0.0 and 3.0 while phi will be in range of 0.0 and 360.0. Both parameters can be changed with `x_range` for theta and `y_range` for phi. +8. `polar_line`, `polar_scatter`: The expected data are pairs of two columns containing the angles and values. +9. `polar_heatmap`: The expected data is a matrix. Each element of the matrix is displayed according to its position inside the matrix. These elements are interpreted as values in theta- and phi-direction. If not given, theta will be in the range of 0.0 and 3.0 while phi will be in range of 0.0 and 360.0. Both parameters can be changed with `x_range` for theta and `y_range` for phi. 10. `quiver`: The expected data are two matrices. The first matrix contains the information about the x-directions and the second matrix the information about the y-directions. 11. `hexbin`, `shade`: The expected data are two columns, representing the x- and y-data. -A plot type that expect the same data shape as other plot types can be converted using an interactive menu. The interaction also yields extra information about the plot, when the mouse is being hovered over them. +A plot type that expect the same data shape as other plot types can be converted using an interactive menu. The interaction also yields extra information about the plot, if the mouse is being hovered over them. ## Editor @@ -136,9 +136,9 @@ The expected data is one column representing the y-data. Possible parameters for the bar plot are: -1. `bar_color`: This parameter defines the color of all bars inside the plot except of those which are referred with `ind_bar_color`. The value of this parameter can either be an integer which represents a color index or three doubles which represent the RGB value of the color. When the parameter isn't set the bars will have the color with index 989 (dark blue). +1. `bar_color`: This parameter defines the color of all bars inside the plot except of those which are referred with `ind_bar_color`. The value of this parameter can either be an integer which represents a color index or three doubles which represent the RGB value of the color. If the parameter isn't set the bars will have the color with index 989 (dark blue). 2. `bar_width`: This parameter defines the width of all bars inside the plot. Depending on the specified width the bars may overlap. The value of this parameter is a double number where its default is 0.8. -3. `edge_color`: This parameter defines the color of all edges inside the plot except of those which are referred with `ind_edge_color`. The value of this parameter can either be an integer which represents a color index or three doubles which represents the RGB value of the color. When the parameter isn't set the edges will have the color with index 1 (black). +3. `edge_color`: This parameter defines the color of all edges inside the plot except of those which are referred with `ind_edge_color`. The value of this parameter can either be an integer which represents a color index or three doubles which represents the RGB value of the color. If the parameter isn't set the edges will have the color with index 1 (black). 4. `edge_width`: This parameter defines the width of all edges inside the plot except those which are referred with `ind_edge_width`. The value of this parameter is a double number where its default is 1.0. 5. `error`: With this parameter the relative error of each bar can be displayed. The values for this parameter are key-value pairs with the following keys: - `error_bar_color`: Defines the color of the error bars as an integer. If no color is given an error is raised. @@ -149,33 +149,34 @@ Possible parameters for the bar plot are: `error:{{error_bar_color:`color_index`},{downwards_cap_color:`color_index`},{upwards_cap_color:`color_index`}}` -6. `ind_bar_color`: With this parameter the color of specific bars can be changed. The value of this parameter are key-value pairs with the following keys: +6. `error_bar_style`: Defines how the error-bars are displayed. As single error-lines(0) or as an error-area(1). +7. `ind_bar_color`: With this parameter the color of specific bars can be changed. The value of this parameter are key-value pairs with the following keys: - `indices`: The index number of the bar, which color should be changed. - `rgb`: The new color for the specified bar. The value has to be three doubles or integer which represents the RGB value. The syntax of this parameter is: `ind_bar_color:`number_of_bars`,{{indices:`first_bar_index`},{rgb:`r1,g1,b1`}`,...`}` -7. `ind_edge_color`: With this parameter the color of specific edges can be changed. The value of this parameter are key-value pairs with the following keys: +8. `ind_edge_color`: With this parameter the color of specific edges can be changed. The value of this parameter are key-value pairs with the following keys: - `indices`: The index number of the edge, which color should be changed. - `rgb`: The new color for the specified edge. The value has to be three doubles or integer which represents the RGB value. The syntax of this parameter is: `ind_edge_color:`number_of_edges`,{{indices:`first_edge_index`},{rgb:`r1,g1,b1`}`,...`}` -8. `ind_edge_width`: With this parameter the width of specific edges can be changed. The value of this parameter are key-value pairs with the following keys: +9. `ind_edge_width`: With this parameter the width of specific edges can be changed. The value of this parameter are key-value pairs with the following keys: - `indices`: The index number of the edge, which width should be changed. - `width`: The new width for the specified edge. The value of this parameter has to be an integer or double. The syntax of this parameter is: `ind_edge_width:`number_of_edges`,{{indices:`first_edge_index`},{width:`first_edge_width`}`,...`}` -9. `orientation`: This parameter defines the orientation of the displayed bars. They can either be drawn `horizontal` or `vertical` while the default is `horizontal`. -10. `style`: This parameter defines how the data inside the bar plot is displayed. There are three options: +10. `orientation`: This parameter defines the orientation of the displayed bars. They can either be drawn `horizontal` or `vertical` while the default is `horizontal`. +11. `style`: This parameter defines how the data inside the bar plot is displayed. There are three options: - `default`: All values are displayed with a separate bar. - `stacked`: The values are displayed with bars which are stacked over each other. - `lined`: The values are displayed with smaller bars next to each other. -11. `y_labels`: This parameter allows the user to set labels to specific bars, which can for example display the value of the bar. The syntax of this parameter is `y_labels:{`label1`,`label2`,`...`}`. +12. `y_labels`: This parameter allows the user to set labels to specific bars, which can for example display the value of the bar. The syntax of this parameter is `y_labels:{`label1`,`label2`,`...`}`. ### CONTOUR @@ -246,7 +247,9 @@ Possible parameters for the histogram are: Note: If the error of the bars is to be displayed, the last two columns of the data are used for the error. If the up and down error are equal use `equal_up_and_down_error` with a value of `1`. In that case only one column is expected for the error data instead of the two. This parameter flag also does not need the `error` parameter to be set. Like by the `error` parameter some of the columns inside the data will get interpreted as error-values. The syntax of this parameter is: `error:{{error_bar_color:`color_index`},{downwards_cap_color:`color_index`},{upwards_cap_color:`color_index`}}` -5. `orientation`: This parameter defines the orientation of the displayed bars. They can either be drawn `horizontal` or `vertical` while the default is `horizontal`. + +5. `error_bar_style`: Defines how the error-bars are displayed. As single error-lines(0) or as an error-area(1). +6. `orientation`: This parameter defines the orientation of the displayed bars. They can either be drawn `horizontal` or `vertical` while the default is `horizontal`. ### IMSHOW @@ -257,7 +260,7 @@ The expected data is a matrix. Each element of the matrix is displayed according Possible parameters for the imshow plot are: 1. `colormap` or `cmap`: This parameter defines the colormap to be used. The default is 44 (viridis). -2. `grplot`: This parameter is there for the consistency between the plot types `contour`, `contourf`, `heatmap`, `imshow`, `marginal_heatmap`, `surface`, `wireframe`. When set the data is displayed in the same order by all of these types where in general the imshow plot would be flipped. The value can be either 0 or 1 where the value if not otherwise set is always 1. +2. `grplot`: This parameter is there for the consistency between the plot types `contour`, `contourf`, `heatmap`, `imshow`, `marginal_heatmap`, `surface`, `wireframe`. If set the data is displayed in the same order by all of these types where in general the imshow plot would be flipped. The value can be either 0 or 1 where the value if not otherwise set is always 1. 3. `x_flip`: This parameter defines whether the x-axis is flipped or not. 4. `y_flip`: This parameter defines whether the y-axis is flipped or not. @@ -282,7 +285,7 @@ The expected data are columns. Each column will be interpreted as a single line. Possible parameters for the line plot are: 1. `error`: With this parameter the relative error of each line can be displayed. The value of this parameter are key-value pairs with the following keys: - - `error_bar_color`: Defines the color of the error bars. The value of this parameter has to be an integer. When no color is given this leads to an error. + - `error_bar_color`: Defines the color of the error bars. The value of this parameter has to be an integer. If no color is given this leads to an error. - `downwards_cap_color`: Defines the downwards cap color of the error bars. The value of this parameter has to be an integer. - `upwards_cap_color`: Defines the upwards cap color of the error bars. The value of this parameter has to be an integer. @@ -290,19 +293,20 @@ Possible parameters for the line plot are: `error:{{error_bar_color:`color_index`},{downwards_cap_color:`color_index`},{upwards_cap_color:`color_index`}}` -2. `int_limits_high`: This parameter defines the upper limits of all integrals. +2. `error_bar_style`: Defines how the error-bars are displayed. As single error-lines(0) or as an error-area(1). +3. `int_limits_high`: This parameter defines the upper limits of all integrals. The syntax for this parameter is: `int_limits_high:`number_of_elements`,`elem_1`,`elem_2`,`... -3. `int_limits_low`: This parameter defines the lower limits of all integrals. +4. `int_limits_low`: This parameter defines the lower limits of all integrals. The syntax for this parameter is: `int_limits_low:`number_of_elements`,`elem_1`,`elem_2`,`... -4. `orientation`: This parameter defines the orientation of the displayed lines. They can either be drawn `horizontal` or `vertical` while the default is `horizontal`. +5. `orientation`: This parameter defines the orientation of the displayed lines. They can either be drawn `horizontal` or `vertical` while the default is `horizontal`. ### MARGINAL_HEATMAP @@ -315,22 +319,16 @@ Possible parameters for the marginal heatmap are: 1. `algorithm`: This parameter defines whether the data is summed up or if the maximum to be used for the side plots. Possible values are `max` and `sum` where the default is `sum`. 2. `colormap` or `cmap`: This parameter defines the colormap to be used. The default is 44 (viridis). 3. `marginal_heatmap_kind` or `h_kind`: This parameter defines what part of the data is displayed inside the side plots. Possible options are: - - `all`: When the kind is set to all, the side plots respect the complete data of the heatmap. This is the default case. - - `line`: When the kind is set to line, the side plots respect only a specific row/column of the data. + - `all`: If the kind is set to all, the side plots respect the complete data of the heatmap. This is the default case. + - `line`: If the kind is set to line, the side plots respect only a specific row/column of the data. 4. `x_flip`: This parameter defines whether the x-axis is flipped or not. 5. `y_flip`: This parameter defines whether the y-axis is flipped or not. -### POLAR - -This plot type converts the data into a polar plot. A polar plot displays a polyline in polar coordinates, with theta indicating the angle in radians and rho indicating the radius value for each point. - -The expected data are two columns containing the angles and values. - ### POLAR_HEATMAP This plot type converts the data into a polar heatmap. A polar heatmap is a heatmap in polar coordinates. -The expected data is a matrix. Each element of the matrix is displayed according to its position inside the matrix. These elements are interpreted as values in phi- and theta-direction. When not given, theta will be in the range of 0.0 and 3.0 while phi will be in range of 0.0 and 360.0. Both parameters can be changed with `x_range` for phi and `y_range` for theta. +The expected data is a matrix. Each element of the matrix is displayed according to its position inside the matrix. These elements are interpreted as values in phi- and theta-direction. If not given, theta will be in the range of 0.0 and 3.0 while phi will be in range of 0.0 and 360.0. Both parameters can be changed with `x_range` for phi and `y_range` for theta. Possible parameters for the polar heatmap are: @@ -347,15 +345,36 @@ Possible parameters for the polar histogram are: 1. `bin_counts`: This parameter sets the amount of classes without binning. 2. `bin_edges`: This parameter sets the borders of the classes. 3. `bin_width`: This parameter sets the width of all the bins. -4. `draw_edges`: When a colormap is used this parameter decides whether the outer shape is drawn or not. The value can be either 0 or 1. -5. `num_bins`: This parameter sets the number of classes which are respected during the binning. -6. `normalization`: This parameter sets the type of normalization for the polar histogram. The value can be `count`, `probability`, `countdensity`, `pdf`, `cumcount` or `cdf`. -7. `phi_flip`: This parameter decides whether the phi values are flipped or not. The value can be either 0 or 1. -8. `stairs`: When this parameter is set, only the outer shapes of the bins are drawn. The value can be either 0 or 1. -9. `x_colormap`: This parameter sets the colormap for the x-direction. -10. `x_flip`: This parameter defines whether the x-axis is flipped or not. -11. `y_colormap`: This parameter sets the colormap for the y-direction. -12. `y_flip`: This parameter defines whether the y-axis is flipped or not. +4. `draw_edges`: If a colormap is used this parameter decides whether the outer shape is drawn or not. The value can be either 0 or 1. +5. `keep_radii_axes`: This parameter only have an impact, if `y_lim` is set. In that case the ranges for the radii axes from `y_lim` get ignored while the polar histogram still gets affected by the `y_lim`. +6. `num_bins`: This parameter sets the number of classes which are respected during the binning. +7. `normalization`: This parameter sets the type of normalization for the polar histogram. The value can be `count`, `probability`, `countdensity`, `pdf`, `cumcount` or `cdf`. +8. `phi_flip`: This parameter decides whether the phi values are flipped or not. The value can be either 0 or 1. +9. `stairs`: If this parameter is set, only the outer shapes of the bins are drawn. The value can be either 0 or 1. +10. `x_colormap`: This parameter sets the colormap for the x-direction. +11. `x_flip`: This parameter defines whether the x-axis is flipped or not. +12. `y_colormap`: This parameter sets the colormap for the y-direction. +13. `y_flip`: This parameter defines whether the y-axis is flipped or not. + +### POLAR_LINE + +This plot type converts the data into a polar plot/line-plot. A polar plot displays a polyline in polar coordinates, with theta indicating the angle in radians and rho indicating the radius value for each point. + +The expected data are two columns containing the angles and values. + +Possible parameters for the polar line plot are: + +1. `clip_negative`: If this parameter is set, only positive radii are displayed, otherwise negative will be mirrored + +### POLAR_SCATTER + +This plot type converts the data into a polar scatter plot. A polar scatter displays each data point as a point inside the polar coordinate system, with theta indicating the angle in radians and rho indicating the radius value for each point. + +The expected data are two columns containing the angles and values. + +Possible parameters for the polar scatter plot are: + +1. `clip_negative`: If this parameter is set, only positive radii are displayed, otherwise negative will be mirrored ### PIE @@ -378,7 +397,7 @@ The expected data are columns. Each column will be interpreted as a single plot. Possible parameters for the scatter plot are: 1. `error`: With this parameter the relative error of each line can be displayed. The value of this parameter are key-value pairs with the following keys: - - `error_bar_color`: Defines the color of the error bars. The value of this parameter has to be an integer. When no color is given this leads to an error. + - `error_bar_color`: Defines the color of the error bars. The value of this parameter has to be an integer. If no color is given this leads to an error. - `downwards_cap_color`: Defines the downwards cap color of the error bars. The value of this parameter has to be an integer. - `upwards_cap_color`: Defines the upwards cap color of the error bars. The value of this parameter has to be an integer. @@ -386,7 +405,8 @@ Possible parameters for the scatter plot are: `error:{{error_bar_color:`color_index`},{downwards_cap_color:`color_index`},{upwards_cap_color:`color_index`}}` -2. `marker_type`: This parameter defines the style of the visualized data points, where the effect belonging to the numbers is the same as for [gr_setmarkertype](https://gr-framework.org/c-gr.html?highlight=gr_setmarkertype#_CPPv416gr_setmarkertypei). +2. `error_bar_style`: Defines how the error-bars are displayed. As single error-lines(0) or as an error-area(1). +3. `marker_type`: This parameter defines the style of the visualized data points, where the effect belonging to the numbers is the same as for [gr_setmarkertype](https://gr-framework.org/c-gr.html?highlight=gr_setmarkertype#_CPPv416gr_setmarkertypei). ### SCATTER3 diff --git a/lib/grm/grplot/gredit/EditElementWidget.cpp b/lib/grm/grplot/gredit/EditElementWidget.cpp new file mode 100644 index 000000000..64cb43712 --- /dev/null +++ b/lib/grm/grplot/gredit/EditElementWidget.cpp @@ -0,0 +1,420 @@ +#include "EditElementWidget.h" + +EditElementWidget::EditElementWidget(GRPlotWidget *widget, QWidget *parent) : QWidget(parent) +{ + grplot_widget = widget; +#if !defined(NO_XERCES_C) + schema_tree = grplot_widget->get_schema_tree(); +#else + schema_tree = nullptr; +#endif +} + +void EditElementWidget::AttributeEditEvent() +{ + auto current_selection = grplot_widget->get_current_selection(); + if (current_selection == nullptr) return; + + if (this->layout() != nullptr) + { + QLayoutItem *item; + while ((item = this->layout()->takeAt(0)) != nullptr) + { + delete item->widget(); + delete item; + } + delete this->layout(); + fields.clear(); + labels.clear(); + attr_type.clear(); + } + + auto combo_box_attr = grplot_widget->getComboBoxAttributes(); + auto check_box_attr = grplot_widget->getCheckBoxAttributes(); + schema_tree = grplot_widget->get_schema_tree(); + + std::string currently_clicked_name = (*current_selection)->get_ref()->localName(); + QString title("Selected: "); + title.append(currently_clicked_name.c_str()); + this->setWindowTitle(title); + auto changeParametersLabel = new QLabel("Change Parameters:"); + changeParametersLabel->setStyleSheet("font-weight: bold"); + auto form = new QFormLayout; + form->addRow(changeParametersLabel); + + QWidget *lineEdit; + + std::vector sorted_names; + for (const auto &cur_attr_name : (*current_selection)->get_ref()->getAttributeNames()) + { + sorted_names.push_back(cur_attr_name); + } + std::sort(sorted_names.begin(), sorted_names.end()); + for (const auto &cur_attr_name : sorted_names) + { + if (util::startsWith(cur_attr_name, "_")) continue; + QString tooltipString = + GRM::Render::getDefaultAndTooltip((*current_selection)->get_ref(), cur_attr_name)[1].c_str(); + tooltipString.append(". Default: "); + tooltipString.append( + GRM::Render::getDefaultAndTooltip((*current_selection)->get_ref(), cur_attr_name)[0].c_str()); + + if (combo_box_attr.contains(cur_attr_name.c_str())) + { + lineEdit = new QComboBox(this); + grplot_widget->advancedAttributeComboBoxHandler(cur_attr_name, (*current_selection)->get_ref()->localName(), + &lineEdit); + if ((*current_selection)->get_ref()->getAttribute(cur_attr_name).isInt()) + { + attr_type.emplace(cur_attr_name, "xs:integer"); + } + else if ((*current_selection)->get_ref()->getAttribute(cur_attr_name).isDouble()) + { + attr_type.emplace(cur_attr_name, "xs:double"); + } + else + { + attr_type.emplace(cur_attr_name, "xs:string"); + } + ((QCheckBox *)lineEdit)->setToolTip(tooltipString); + } + else if (check_box_attr.contains(cur_attr_name.c_str())) + { + lineEdit = new QCheckBox(this); + ((QCheckBox *)lineEdit)->setToolTip(tooltipString); + ((QCheckBox *)lineEdit) + ->setChecked(static_cast((*current_selection)->get_ref()->getAttribute(cur_attr_name)) == 1); + } + else + { + if ((*current_selection)->get_ref()->getAttribute(cur_attr_name).isInt()) + { + attr_type.emplace(cur_attr_name, "xs:integer"); + } + else if ((*current_selection)->get_ref()->getAttribute(cur_attr_name).isDouble()) + { + attr_type.emplace(cur_attr_name, "xs:double"); + } + else + { + attr_type.emplace(cur_attr_name, "xs:string"); + } + lineEdit = new QLineEdit(this); + ((QLineEdit *)lineEdit) + ->setText(static_cast((*current_selection)->get_ref()->getAttribute(cur_attr_name)).c_str()); + ((QLineEdit *)lineEdit)->setToolTip(tooltipString); + } + QString text_label = QString(cur_attr_name.c_str()); + form->addRow(text_label, lineEdit); + + labels << text_label; + fields << lineEdit; + } + + if (schema_tree != nullptr) + { + std::shared_ptr element; + auto selections = schema_tree->querySelectorsAll("[name=" + currently_clicked_name + "]"); + for (const auto &selection : selections) + { + if (selection->localName() == "xs:element") element = selection->children()[0]; + } + + /* iterate through complextype elements */ + for (const auto &child : element->children()) + { + if (child->localName() == "xs:attribute") + { + auto attr_name = static_cast(child->getAttribute("name")); + if (!(*current_selection)->get_ref()->hasAttribute(attr_name)) + { + /* attributes of an element which aren't already in the tree getting added with red text color + */ + auto type_name = static_cast(child->getAttribute("type")); + attr_type.emplace(attr_name, type_name); + QString tooltipString = + GRM::Render::getDefaultAndTooltip((*current_selection)->get_ref(), attr_name)[1].c_str(); + tooltipString.append(". Default: "); + tooltipString.append( + GRM::Render::getDefaultAndTooltip((*current_selection)->get_ref(), attr_name)[0].c_str()); + + if (combo_box_attr.contains(attr_name.c_str())) + { + lineEdit = new QComboBox(this); + grplot_widget->advancedAttributeComboBoxHandler( + attr_name, (*current_selection)->get_ref()->localName(), &lineEdit); + ((QCheckBox *)lineEdit)->setToolTip(tooltipString); + } + else if (check_box_attr.contains(attr_name.c_str())) + { + lineEdit = new QCheckBox(this); + ((QCheckBox *)lineEdit)->setToolTip(tooltipString); + ((QCheckBox *)lineEdit) + ->setChecked(static_cast((*current_selection)->get_ref()->getAttribute(attr_name)) == 1); + } + else + { + lineEdit = new QLineEdit(this); + ((QLineEdit *)lineEdit)->setToolTip(tooltipString); + ((QLineEdit *)lineEdit)->setText(""); + } + QString text_label = QString("%1").arg(attr_name.c_str()); + form->addRow(text_label, lineEdit); + + labels << text_label; + fields << lineEdit; + } + } + else if (child->localName() == "xs:attributegroup") + { + /* when an element contains one or more attributegroups all attributes from these groups must be + * added */ + std::shared_ptr group; + auto group_name = static_cast(child->getAttribute("ref")); + + if (group_name != "colorrep") + { + auto attr_group_selections = schema_tree->querySelectorsAll("[name=" + group_name + "]"); + for (const auto &selection : attr_group_selections) + { + if (selection->localName() == "xs:attributegroup") group = selection; + } + + /* iterate through attribute elements */ + for (const auto &childchild : group->children()) + { + if (childchild->localName() == "xs:attribute") + { + auto attr_name = static_cast(childchild->getAttribute("name")); + if (!(*current_selection)->get_ref()->hasAttribute(attr_name)) + { + /* attributes of an element which aren't already in the tree getting added with + * red text color */ + auto type_name = static_cast(childchild->getAttribute("type")); + attr_type.emplace(attr_name, type_name); + QString tooltipString = + GRM::Render::getDefaultAndTooltip((*current_selection)->get_ref(), attr_name)[1] + .c_str(); + tooltipString.append(". Default: "); + tooltipString.append( + GRM::Render::getDefaultAndTooltip((*current_selection)->get_ref(), attr_name)[0] + .c_str()); + + if (combo_box_attr.contains(attr_name.c_str())) + { + lineEdit = new QComboBox(this); + grplot_widget->advancedAttributeComboBoxHandler( + attr_name, (*current_selection)->get_ref()->localName(), &lineEdit); + ((QCheckBox *)lineEdit)->setToolTip(tooltipString); + } + else if (check_box_attr.contains(attr_name.c_str())) + { + lineEdit = new QCheckBox(this); + ((QCheckBox *)lineEdit)->setToolTip(tooltipString); + ((QCheckBox *)lineEdit) + ->setChecked(static_cast( + (*current_selection)->get_ref()->getAttribute(attr_name)) == 1); + } + else + { + lineEdit = new QLineEdit(this); + ((QLineEdit *)lineEdit)->setToolTip(tooltipString); + ((QLineEdit *)lineEdit)->setText(""); + } + QString text_label = + QString("%1").arg(attr_name.c_str()); + form->addRow(text_label, lineEdit); + + labels << text_label; + fields << lineEdit; + } + } + } + } + else + { + /* special case for colorrep cause there are way to many attributes inside the attributegroup + */ + lineEdit = new QLineEdit(this); + ((QLineEdit *)lineEdit)->setText(""); + QString text_label = QString("%1").arg("Colorrep-index"); + form->addRow(text_label, lineEdit); + + attr_type.emplace("Colorrep-index", "xs:string"); + labels << text_label; + fields << lineEdit; + + lineEdit = new QLineEdit(this); + ((QLineEdit *)lineEdit)->setText(""); + text_label = QString("%1").arg("Colorrep-value"); + form->addRow(text_label, lineEdit); + + attr_type.emplace("Colorrep-value", "xs:string"); + labels << text_label; + fields << lineEdit; + } + } + } + } + + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal); + QObject::connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + form->addRow(buttonBox); + + auto scrollAreaContent = new QWidget; + scrollAreaContent->setLayout(form); + + auto scrollArea = new QScrollArea; + scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + scrollArea->setWidgetResizable(true); + scrollArea->setWidget(scrollAreaContent); + + auto groupBoxLayout = new QVBoxLayout; + groupBoxLayout->addWidget(scrollArea); + this->setLayout(groupBoxLayout); + this->resize(std::min(grplot_widget->width(), form->sizeHint().width() + this->layout()->sizeHint().width()), + std::min(grplot_widget->height(), form->sizeHint().height() + this->layout()->sizeHint().height())); +} + +void EditElementWidget::reject() +{ + grplot_widget->setTreeUpdate(false); + fields.clear(); + labels.clear(); + attr_type.clear(); + this->close(); +} + +void EditElementWidget::accept() +{ + auto current_selection = grplot_widget->get_current_selection(); + for (int i = 0; i < labels.count(); i++) + { + auto &field = *fields[i]; // because typeid(*fields[i]) is bad :( + if (util::startsWith(labels[i].toStdString(), "") && + util::endsWith(labels[i].toStdString(), "")) + { + labels[i].remove(0, 29); + labels[i].remove(labels[i].size() - 7, 7); + } + std::string attr_name = labels[i].toStdString(); + if (typeid(field) == typeid(QLineEdit) && ((QLineEdit *)fields[i])->isModified()) + { + std::string name = std::string((*current_selection)->get_ref()->getAttribute("name")); + if (((QLineEdit *)fields[i])->text().toStdString().empty() && labels[i].toStdString() != "tick_label" && + labels[i].toStdString() != "text") + { + /* remove attributes from tree when the value got removed */ + (*current_selection)->get_ref()->removeAttribute(labels[i].toStdString()); + } + else + { + if (labels[i].toStdString() == "text") + { + const std::string value = ((QLineEdit *)fields[i])->text().toStdString(); + if (attr_type[attr_name] == "xs:string" || + (attr_type[attr_name] == "strint" && !util::is_digits(value))) + { + if ((*current_selection)->get_ref()->parentElement()->localName() == "text_region") + { + (*current_selection) + ->get_ref() + ->parentElement() + ->parentElement() + ->setAttribute("text_content", value); + } + else if (name == "xlabel" || name == "ylabel") + { + (*current_selection) + ->get_ref() + ->parentElement() + ->parentElement() + ->querySelectors(name) + ->setAttribute(name, value); + } + } + else if (attr_type[attr_name] == "xs:double") + { + (*current_selection) + ->get_ref() + ->parentElement() + ->setAttribute(labels[i].toStdString(), std::stod(value)); + } + else if (attr_type[attr_name] == "xs:integer" || + (attr_type[attr_name] == "strint" && util::is_digits(value))) + { + (*current_selection) + ->get_ref() + ->parentElement() + ->setAttribute(labels[i].toStdString(), std::stoi(value)); + } + } + if (labels[i].toStdString() == "Colorrep-index") + { + /* special case for colorrep attribute */ + (*current_selection) + ->get_ref() + ->setAttribute("colorrep." + ((QLineEdit *)fields[i])->text().toStdString(), + ((QLineEdit *)fields[i + 1])->text().toStdString()); + } + else if (labels[i].toStdString() != "Colorrep-value") + { + const std::string value = ((QLineEdit *)fields[i])->text().toStdString(); + if (attr_type[attr_name] == "xs:string" || + (attr_type[attr_name] == "strint" && !util::is_digits(value))) + { + (*current_selection)->get_ref()->setAttribute(labels[i].toStdString(), value); + } + else if (attr_type[attr_name] == "xs:double") + { + (*current_selection)->get_ref()->setAttribute(labels[i].toStdString(), std::stod(value)); + } + else if (attr_type[attr_name] == "xs:integer" || + (attr_type[attr_name] == "strint" && util::is_digits(value))) + { + (*current_selection)->get_ref()->setAttribute(labels[i].toStdString(), std::stoi(value)); + } + } + } + } + else if (typeid(field) == typeid(QComboBox)) + { + int index = ((QComboBox *)fields[i])->currentIndex(); + if (((QComboBox *)fields[i])->itemText(index).toStdString().empty()) + { + /* remove attributes from tree when the value got removed */ + (*current_selection)->get_ref()->removeAttribute(labels[i].toStdString()); + } + else + { + const std::string value = ((QComboBox *)fields[i])->itemText(index).toStdString(); + grplot_widget->attributeSetForComboBox(attr_type[attr_name], (*current_selection)->get_ref(), value, + (labels[i]).toStdString()); + } + } + else if (typeid(field) == typeid(QCheckBox)) + { + (*current_selection)->get_ref()->setAttribute(labels[i].toStdString(), ((QCheckBox *)fields[i])->isChecked()); + } + } + grplot_widget->setTreeUpdate(true); + if (getenv("GRM_DEBUG")) + { + std::cerr << toXML(grm_get_document_root(), + GRM::SerializerOptions{std::string(2, ' '), + GRM::SerializerOptions::InternalAttributesFormat::Plain}) + << "\n"; + } + grplot_widget->editElementAccepted(); + fields.clear(); + labels.clear(); + attr_type.clear(); + this->close(); +} + +void EditElementWidget::keyPressEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) accept(); +} diff --git a/lib/grm/grplot/gredit/EditElementWidget.h b/lib/grm/grplot/gredit/EditElementWidget.h new file mode 100644 index 000000000..7d1343ea6 --- /dev/null +++ b/lib/grm/grplot/gredit/EditElementWidget.h @@ -0,0 +1,44 @@ +#ifndef EDITELEMENTWIDGET_H +#define EDITELEMENTWIDGET_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "grm.h" +class EditElementWidget; +#include "../grplot_widget.hxx" + + +class EditElementWidget : public QWidget +{ + Q_OBJECT +public: + explicit EditElementWidget(GRPlotWidget *widget, QWidget *parent = nullptr); + + void AttributeEditEvent(); + +private slots: + void reject(); + void accept(); + +protected: + void keyPressEvent(QKeyEvent *event) override; + +private: + GRPlotWidget *grplot_widget; + std::shared_ptr schema_tree; + QList labels; + QList fields; + std::unordered_map attr_type; +}; + + +#endif // EDITELEMENTWIDGET_H diff --git a/lib/grm/grplot/gredit/TableWidget.cpp b/lib/grm/grplot/gredit/TableWidget.cpp new file mode 100644 index 000000000..a76532a9b --- /dev/null +++ b/lib/grm/grplot/gredit/TableWidget.cpp @@ -0,0 +1,247 @@ +#include "TableWidget.h" + +#include +#include +#include + + +TableWidget::TableWidget(GRPlotWidget *widget, QWidget *parent) : QTableWidget(parent) +{ + grplot_widget = widget; + this->setWindowTitle("DOM-Tree Data-Context Viewer"); + this->setRowCount(2); + this->setVerticalHeaderItem(0, new QTableWidgetItem("Context-Key")); +} + +std::map> +TableWidget::extractContextNames(const std::shared_ptr context) +{ + int col_cnt = 0; + std::map> context_data; + std::vector cntxt_names; + + context_data = grm_get_context_data(); + + for (const auto &entry : context_data) + { + col_cnt += 1; + cntxt_names.push_back(entry.first); + } + this->col_num = col_cnt; + this->context_names = cntxt_names; + return context_data; +} + +void TableWidget::updateData(const std::shared_ptr context) +{ + int max_rows = 0, col = 0; + std::map> context_data; + + // disconnect so that a reread wont trigger applyTableChanges + disconnect(this, SIGNAL(cellChanged(int, int)), this, SLOT(applyTableChanges(int, int))); + this->context = context; + this->context_attributes = getContextAttributes(); + + context_data = extractContextNames(context); + this->setColumnCount(this->col_num); + + for (const auto &entry : context_data) + { + int row = 1; + this->setItem(0, col, new QTableWidgetItem(entry.first.c_str())); + max_rows = std::max(max_rows, (int)entry.second.size() + 1); + this->setRowCount(max_rows); + for (const auto &str : entry.second) + { + this->setItem(row, col, new QTableWidgetItem(str.c_str())); + row += 1; + } + col += 1; + } + + for (int i = 1; i <= max_rows; i++) + { + this->setVerticalHeaderItem(i, new QTableWidgetItem(std::to_string(i).c_str())); + } + + connect(this, SIGNAL(cellChanged(int, int)), this, SLOT(applyTableChanges(int, int))); + connect(this, SIGNAL(cellClicked(int, int)), this, SLOT(showUsagesOfContext(int, int))); +} + +void TableWidget::applyTableChanges(int row, int column) +{ + std::string new_value = this->item(row, column)->text().toStdString(); + + if (getenv("GRM_DEBUG")) + fprintf(stderr, "Detected change at (%i/%i) with value '%s'. Old value was '%s'\n", row, column, new_value.c_str(), + this->context_names[column].c_str()); + + if (row != 0) + { + // data has been changed -> apply these changes to the context + auto context_key = this->item(0, column)->text().toStdString(); + + if ((*this->context)[context_key].doubleUsed()) + { + auto vec = GRM::get>((*this->context)[context_key]); + if (vec.size() > row) + { + vec[row - 1] = atof(new_value.c_str()); + (*this->context)[context_key] = vec; + } + else + { + // only allow to edit non empty lines to prevent multiple complications with size mismatches + this->item(row, column)->setText(""); + } + } + else if ((*this->context)[context_key].intUsed()) + { + auto vec = GRM::get>((*this->context)[context_key]); + if (vec.size() > row) + { + vec[row - 1] = atoi(new_value.c_str()); + (*this->context)[context_key] = vec; + } + else + { + // only allow to edit non empty lines to prevent multiple complications with size mismatches + this->item(row, column)->setText(""); + } + } + else + { + auto vec = GRM::get>((*this->context)[context_key]); + if (vec.size() > row) + { + vec[row - 1] = new_value; + (*this->context)[context_key] = vec; + } + else + { + // only allow to edit non empty lines to prevent multiple complications with size mismatches + this->item(row, column)->setText(""); + } + } + this->grplot_widget->redraw(); + } + else + { + // the name of the context got changed -> replace the key inside the context and update tree attributes + auto context_key = this->context_names[column].c_str(); + + if ((*this->context)[context_key].doubleUsed()) + { + auto vec = GRM::get>((*this->context)[context_key]); + (*this->context)[new_value] = vec; + } + else if ((*this->context)[context_key].intUsed()) + { + auto vec = GRM::get>((*this->context)[context_key]); + (*this->context)[new_value] = vec; + } + else + { + auto vec = GRM::get>((*this->context)[context_key]); + (*this->context)[new_value] = vec; + } + addValidContextKey(new_value); // add the name to valid keys so it could also be exported and updated + + // get the plain XML-tree and use the string find option to get attr=value -> use this information to select the + // tree element and update the value with the new context name + // all that is needed cause u can't search just for the value with the selector + auto tree_str = GRM::toXML( + grm_get_document_root(), + GRM::SerializerOptions{std::string(2, ' '), GRM::SerializerOptions::InternalAttributesFormat::Plain}); + std::string token = "=\"" + std::string(context_key) + "\""; + while (tree_str.find(token) != std::string::npos) + { + int max_attr_length = 50; + auto pos = tree_str.find(token); + auto interesting_part = + tree_str.substr(std::max(0, pos - max_attr_length), max_attr_length + token.size()); + auto start = interesting_part.find_last_of(" "); + auto selector_token = interesting_part.substr(start + 1, (max_attr_length - start - 1) + token.size()); + auto attr = interesting_part.substr(start + 1, (max_attr_length - start - 1)); + tree_str = tree_str.substr(pos + token.size(), std::string::npos); + + if (getenv("GRM_DEBUG")) + fprintf(stderr, "Replace the value of %s with the new user-defined name\n", selector_token.c_str()); + + if (std::find(this->context_attributes.begin(), this->context_attributes.end(), attr) == + this->context_attributes.end()) + continue; + for (const auto &elem : grm_get_document_root()->querySelectorsAll("[" + selector_token + "]")) + { + if (static_cast(elem->getAttribute(attr)) == std::string(context_key)) + { + elem->setAttribute(attr, new_value); + (*this->context)[context_key].decrement_key(context_key); + break; + } + } + } + } +} + +void TableWidget::showUsagesOfContext(int row, int column) +{ + referenced_attributes.clear(); + if (row == 0) + { + auto context_ref_name = this->item(row, column)->text().toStdString(); + + // get the plain XML-tree and use the string find option to get attr=value -> use this information to select the + // tree element and update the value with the new context name + // all that is needed cause u can't search just for the value with the selector + auto tree_str = GRM::toXML( + grm_get_document_root(), + GRM::SerializerOptions{std::string(2, ' '), GRM::SerializerOptions::InternalAttributesFormat::Plain}); + std::string token = "=\"" + std::string(context_ref_name) + "\""; + while (tree_str.find(token) != std::string::npos) + { + int max_attr_length = 50; + auto pos = tree_str.find(token); + auto interesting_part = + tree_str.substr(std::max(0, pos - max_attr_length), max_attr_length + token.size()); + auto start = interesting_part.find_last_of(" "); + auto selector_token = interesting_part.substr(start + 1, (max_attr_length - start - 1) + token.size()); + auto attr = interesting_part.substr(start + 1, (max_attr_length - start - 1)); + tree_str = tree_str.substr(pos + token.size(), std::string::npos); + + if (std::find(this->context_attributes.begin(), this->context_attributes.end(), attr) == + this->context_attributes.end()) + continue; + for (const auto &elem : grm_get_document_root()->querySelectorsAll("[" + selector_token + "]")) + { + bool skip = false; + if (static_cast(elem->getAttribute(attr)) == std::string(context_ref_name)) + { + auto bbox_id = static_cast(elem->getAttribute("_bbox_id")); + auto bbox_x_min = static_cast(elem->getAttribute("_bbox_x_min")); + auto bbox_x_max = static_cast(elem->getAttribute("_bbox_x_max")); + auto bbox_y_min = static_cast(elem->getAttribute("_bbox_y_min")); + auto bbox_y_max = static_cast(elem->getAttribute("_bbox_y_max")); + const Bounding_object bbox = + Bounding_object(bbox_id, bbox_x_min, bbox_x_max, bbox_y_min, bbox_y_max, elem); + for (const auto &vec_elem : referenced_attributes) + { + if (vec_elem.get_ref() == elem) + { + skip = true; + break; + } + } + if (!skip) referenced_attributes.emplace_back(bbox); + } + } + } + } + this->grplot_widget->set_referenced_elements(this->referenced_attributes); + this->grplot_widget->redraw(); +} + +std::vector TableWidget::getContextNames() +{ + return this->context_names; +} diff --git a/lib/grm/grplot/gredit/TableWidget.h b/lib/grm/grplot/gredit/TableWidget.h new file mode 100644 index 000000000..adeb88167 --- /dev/null +++ b/lib/grm/grplot/gredit/TableWidget.h @@ -0,0 +1,33 @@ +#ifndef TABLEWIDGET_H +#define TABLEWIDGET_H + +#include +#include + +class TableWidget; +#include "../grplot_widget.hxx" + +class TableWidget : public QTableWidget +{ + Q_OBJECT +public: + explicit TableWidget(GRPlotWidget *widget, QWidget *parent = nullptr); + std::map> extractContextNames(const std::shared_ptr context); + void updateData(std::shared_ptr context); + std::vector getContextNames(); + +private slots: + void applyTableChanges(int row, int column); + void showUsagesOfContext(int row, int column); + +private: + GRPlotWidget *grplot_widget; + std::shared_ptr context; + std::vector context_names; + std::vector context_attributes; + std::vector referenced_attributes; + int col_num; +}; + + +#endif // TABLEWIDGET_H diff --git a/lib/grm/grplot/grplot.cxx b/lib/grm/grplot/grplot.cxx index 0620db609..ec8003199 100644 --- a/lib/grm/grplot/grplot.cxx +++ b/lib/grm/grplot/grplot.cxx @@ -30,7 +30,7 @@ int main(int argc, char **argv) #else std::cerr << e.what() << std::endl; #endif - std::cerr << "Failed to set the \"GRDIR\" envionment variable, falling back to GRDIR=\"" << GRDIR << "\"." + std::cerr << "Failed to set the \"GRDIR\" environment variable, falling back to GRDIR=\"" << GRDIR << "\"." << std::endl; } diff --git a/lib/grm/grplot/grplot.pro b/lib/grm/grplot/grplot.pro index c3723aabd..c62d0fb17 100644 --- a/lib/grm/grplot/grplot.pro +++ b/lib/grm/grplot/grplot.pro @@ -11,8 +11,8 @@ DEFINES += GRDIR=\\\"$(GRDIR)\\\" QMAKE_CXXFLAGS += -std=c++17 $$(XERCESCDEFS) $$(EXTRA_CXXFLAGS) QMAKE_LFLAGS += $$(EXTRA_LDFLAGS) QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.15 -HEADERS += grplot_widget.hxx grplot_mainwindow.hxx util.hxx gredit/Bounding_logic.h gredit/Bounding_object.h gredit/CustomTreeWidgetItem.h gredit/TreeWidget.h gredit/AddElementWidget.h qtterm/grm_args_t_wrapper.h qtterm/receiver_thread.h -SOURCES += grplot_widget.cxx grplot.cxx grplot_mainwindow.cxx util.cxx gredit/Bounding_logic.cpp gredit/Bounding_object.cpp gredit/CustomTreeWidgetItem.cpp gredit/TreeWidget.cpp gredit/AddElementWidget.cpp qtterm/grm_args_t_wrapper.cpp qtterm/receiver_thread.cpp +HEADERS += grplot_widget.hxx grplot_mainwindow.hxx util.hxx gredit/Bounding_logic.h gredit/Bounding_object.h gredit/CustomTreeWidgetItem.h gredit/TreeWidget.h gredit/AddElementWidget.h gredit/TableWidget.h gredit/EditElementWidget.h qtterm/grm_args_t_wrapper.h qtterm/receiver_thread.h +SOURCES += grplot_widget.cxx grplot.cxx grplot_mainwindow.cxx util.cxx gredit/Bounding_logic.cpp gredit/Bounding_object.cpp gredit/CustomTreeWidgetItem.cpp gredit/TreeWidget.cpp gredit/AddElementWidget.cpp gredit/TableWidget.cpp gredit/EditElementWidget.cpp qtterm/grm_args_t_wrapper.cpp qtterm/receiver_thread.cpp INCLUDEPATH += ../include ../../gr if (macx) { if (exists(../libGRM.dylib)) { diff --git a/lib/grm/grplot/grplot_widget.cxx b/lib/grm/grplot/grplot_widget.cxx index 6afa34dfd..815eaa5db 100644 --- a/lib/grm/grplot/grplot_widget.cxx +++ b/lib/grm/grplot/grplot_widget.cxx @@ -1,7 +1,4 @@ #include -#include -#include -#include #include #include #include @@ -13,20 +10,14 @@ #include #include -#include -#include -#include -#include #include #include #include #include #include #include -#include #include #include -#include #include #include #include @@ -101,6 +92,10 @@ GRPlotWidget::GRPlotWidget(QMainWindow *parent, int argc, char **argv) amount_scrolled = 0; treewidget = new TreeWidget(this); treewidget->hide(); + table_widget = new TableWidget(this); + table_widget->hide(); + edit_element_widget = new EditElementWidget(this); + edit_element_widget->hide(); selected_parent = nullptr; csr = new QCursor(Qt::ArrowCursor); setCursor(*csr); @@ -108,7 +103,9 @@ GRPlotWidget::GRPlotWidget(QMainWindow *parent, int argc, char **argv) combo_box_attr = QStringList{ "algorithm", "axis_type", + "clip_region", "colormap", + "error_bar_style", "font", "font_precision", "kind", @@ -142,6 +139,7 @@ GRPlotWidget::GRPlotWidget(QMainWindow *parent, int argc, char **argv) "adjust_x_lim", "adjust_y_lim", "adjust_z_lim", + "clip_negative", "disable_x_trans", "disable_y_trans", "draw_grid", @@ -150,12 +148,14 @@ GRPlotWidget::GRPlotWidget(QMainWindow *parent, int argc, char **argv) "is_major", "is_mirrored", "keep_aspect_ratio", + "keep_radii_axes", "keep_window", "marginal_heatmap_side_plot", "mirrored_axis", "movable", "only_quadratic_aspect_ratio", "phi_flip", + "polar_with_pan", "set_text_color_for_background", "space", "stairs", @@ -172,6 +172,13 @@ GRPlotWidget::GRPlotWidget(QMainWindow *parent, int argc, char **argv) "z_log", }; + // add context attributes to combobox list + auto context_attributes = getContextAttributes(); + for (const auto &attr : context_attributes) + { + combo_box_attr.push_back(attr.c_str()); + } + #ifdef _WIN32 putenv("GKS_WSTYPE=381"); putenv("GKS_DOUBLE_BUF=True"); @@ -354,7 +361,7 @@ GRPlotWidget::GRPlotWidget(QMainWindow *parent, int argc, char **argv) connect(histAct, &QAction::triggered, this, &GRPlotWidget::hist); barplotAct = new QAction(tr("&Barplot"), this); connect(barplotAct, &QAction::triggered, this, &GRPlotWidget::barplot); - stairsAct = new QAction(tr("&Step"), this); + stairsAct = new QAction(tr("&Stairs"), this); connect(stairsAct, &QAction::triggered, this, &GRPlotWidget::stairs); stemAct = new QAction(tr("&Stem"), this); connect(stemAct, &QAction::triggered, this, &GRPlotWidget::stem); @@ -372,6 +379,15 @@ GRPlotWidget::GRPlotWidget(QMainWindow *parent, int argc, char **argv) type->addAction(shadeAct); type->addAction(hexbinAct); } + else if (strcmp(kind, "polar_line") == 0 || strcmp(kind, "polar_scatter") == 0) + { + polarLineAct = new QAction(tr("&Polar Line"), this); + connect(polarLineAct, &QAction::triggered, this, &GRPlotWidget::polar_line); + polarScatterAct = new QAction(tr("&Polar Scatter"), this); + connect(polarScatterAct, &QAction::triggered, this, &GRPlotWidget::polar_scatter); + type->addAction(polarLineAct); + type->addAction(polarScatterAct); + } moveableModeAct = new QAction(tr("&Disable movable transformation"), this); connect(moveableModeAct, &QAction::triggered, this, &GRPlotWidget::moveableMode); modi_menu->addAction(moveableModeAct); @@ -434,7 +450,28 @@ GRPlotWidget::GRPlotWidget(QMainWindow *parent, int argc, char **argv) QObject::connect(add_element_action, SIGNAL(triggered()), this, SLOT(add_element_slot())); add_element_action->setVisible(false); - if (strcmp(argv[1], "--test") != 0 && !test_commands_stream) menu->addMenu(editor_menu); + context_menu = new QMenu("&Data"); + add_context_data = new QMenu("Add Data-Context"); + show_context_action = new QAction(tr("&Display Data-Context")); + show_context_action->setCheckable(true); + QObject::connect(show_context_action, SIGNAL(triggered()), this, SLOT(showContextSlot())); + context_menu->addAction(show_context_action); + add_context_action = new QAction(tr("&Column files")); + QObject::connect(add_context_action, SIGNAL(triggered()), this, SLOT(addContextSlot())); + add_context_data->addAction(add_context_action); + add_grplot_data_context = new QAction(tr("&Interpret matrix as 1 column data")); + QObject::connect(add_grplot_data_context, SIGNAL(triggered()), this, SLOT(addGRPlotDataContextSlot())); + add_context_data->addAction(add_grplot_data_context); + generate_linear_context_action = new QAction(tr("&Generate linear Data-Context")); + QObject::connect(generate_linear_context_action, SIGNAL(triggered()), this, SLOT(generateLinearContextSlot())); + add_context_data->addAction(generate_linear_context_action); + + if (strcmp(argv[1], "--test") != 0 && !test_commands_stream) + { + menu->addMenu(editor_menu); + menu->addMenu(context_menu); + context_menu->addMenu(add_context_data); + } } global_root = grm_get_document_root(); } @@ -457,7 +494,8 @@ void GRPlotWidget::attributeComboBoxHandler(const std::string &cur_attr_name, st QWidget **lineEdit) { QStringList size_unit_list, colormap_list, font_list, font_precision_list, line_type_list, location_list, - marker_type_list, text_align_horizontal_list, text_align_vertical_list, algorithm_volume_list, model_list; + marker_type_list, text_align_horizontal_list, text_align_vertical_list, algorithm_volume_list, model_list, + context_attr_list; auto size_unit_vec = getSizeUnits(); size_unit_list.reserve((int)size_unit_vec.size()); for (auto &i : size_unit_vec) @@ -524,11 +562,22 @@ void GRPlotWidget::attributeComboBoxHandler(const std::string &cur_attr_name, st { model_list.push_back(i.c_str()); } + table_widget->extractContextNames(grm_get_render()->getContext()); + auto context_attr_vec = table_widget->getContextNames(); + context_attr_list.reserve((int)context_attr_vec.size()); + for (auto &i : context_attr_vec) + { + context_attr_list.push_back(i.c_str()); + } QStringList axis_type_list{ "x", "y", }; + QStringList clip_region_list{ + "quadratic", + "elliptic", + }; QStringList orientation_list{ "vertical", "horizontal", @@ -537,6 +586,10 @@ void GRPlotWidget::attributeComboBoxHandler(const std::string &cur_attr_name, st "sum", "max", }; + QStringList error_bar_style_list{ + "line", + "area", + }; QStringList marginal_heatmap_kind_list{ "all", "line", @@ -591,6 +644,8 @@ void GRPlotWidget::attributeComboBoxHandler(const std::string &cur_attr_name, st QStringList side_region_location_list{"top", "right", "bottom", "left"}; static std::map attributeToList{ {"axis_type", axis_type_list}, + {"error_bar_style", error_bar_style_list}, + {"clip_region", clip_region_list}, {"size_x_unit", size_unit_list}, {"size_y_unit", size_unit_list}, {"colormap", colormap_list}, @@ -618,6 +673,14 @@ void GRPlotWidget::attributeComboBoxHandler(const std::string &cur_attr_name, st {"z_org_pos", org_pos_list}, {"tick_orientation", tick_orientation_list}, }; + // add for all context attributes all possible values + for (const auto &attr : getContextAttributes()) + { + if (attributeToList.count(attr) >= 1) + attributeToList[attr] = context_attr_list; + else + attributeToList.emplace(attr, context_attr_list); + } ((QComboBox *)*lineEdit)->setEditable(true); if (attributeToList.count(cur_attr_name)) @@ -661,7 +724,7 @@ void GRPlotWidget::attributeComboBoxHandler(const std::string &cur_attr_name, st QStringList plot3_group = {"plot3", "scatter", "scatter3", "tricontour", "trisurface"}; QStringList barplot_group = {"barplot", "hist", "stem", "stairs"}; QStringList hexbin_group = {"hexbin", "shade"}; - QStringList other_kinds = {"pie", "polar_histogram", "polar", "polar_heatmap", "polar_histogram", "quiver"}; + QStringList other_kinds = {"pie", "polar_heatmap", "polar_histogram", "polar_line", "polar_scatter", "quiver"}; std::string kind; if (util::startsWith(cur_elem_name, "series_")) kind = cur_elem_name.erase(0, 7); @@ -771,6 +834,10 @@ void GRPlotWidget::advancedAttributeComboBoxHandler(const std::string &cur_attr_ { current_text = locationIntToString(static_cast(current_selection->get_ref()->getAttribute(cur_attr_name))); } + else if (cur_attr_name == "clip_region" && current_selection->get_ref()->getAttribute(cur_attr_name).isInt()) + { + current_text = clipRegionIntToString(static_cast(current_selection->get_ref()->getAttribute(cur_attr_name))); + } else if (cur_attr_name == "colormap" && current_selection->get_ref()->getAttribute(cur_attr_name).isInt()) { current_text = colormapIntToString(static_cast(current_selection->get_ref()->getAttribute(cur_attr_name))); @@ -797,6 +864,11 @@ void GRPlotWidget::advancedAttributeComboBoxHandler(const std::string &cur_attr_ { current_text = lineTypeIntToString(static_cast(current_selection->get_ref()->getAttribute(cur_attr_name))); } + else if (cur_attr_name == "resample_method" && current_selection->get_ref()->getAttribute(cur_attr_name).isInt()) + { + current_text = + resampleMethodIntToString(static_cast(current_selection->get_ref()->getAttribute(cur_attr_name))); + } else if (cur_attr_name == "scientific_format" && current_selection->get_ref()->getAttribute(cur_attr_name).isInt()) { current_text = @@ -807,6 +879,11 @@ void GRPlotWidget::advancedAttributeComboBoxHandler(const std::string &cur_attr_ current_text = tickOrientationIntToString(static_cast(current_selection->get_ref()->getAttribute(cur_attr_name))); } + else if (cur_attr_name == "error_bar_style" && current_selection->get_ref()->getAttribute(cur_attr_name).isInt()) + { + current_text = + errorBarStyleIntToString(static_cast(current_selection->get_ref()->getAttribute(cur_attr_name))); + } int index = ((QComboBox *)*lineEdit)->findText(current_text.c_str()); if (index == -1) index += ((QComboBox *)*lineEdit)->count(); ((QComboBox *)*lineEdit)->setCurrentIndex(index); @@ -845,6 +922,10 @@ void GRPlotWidget::attributeSetForComboBox(const std::string &attr_type, std::sh { element->setAttribute(label, locationStringToInt(value)); } + else if (label == "clip_region") + { + element->setAttribute(label, clipRegionStringToInt(value)); + } else if (label == "colormap") { element->setAttribute(label, colormapStringToInt(value)); @@ -869,6 +950,10 @@ void GRPlotWidget::attributeSetForComboBox(const std::string &attr_type, std::sh { element->setAttribute(label, lineTypeStringToInt(value)); } + else if (label == "resample_method") + { + element->setAttribute(label, resampleMethodStringToInt(value)); + } else if (label == "tick_orientation") { element->setAttribute(label, tickOrientationStringToInt(value)); @@ -877,6 +962,10 @@ void GRPlotWidget::attributeSetForComboBox(const std::string &attr_type, std::sh { element->setAttribute(label, scientificFormatStringToInt(value)); } + else if (label == "error_bar_style") + { + element->setAttribute(label, errorBarStyleStringToInt(value)); + } else { element->setAttribute(label, std::stoi(value)); @@ -886,370 +975,8 @@ void GRPlotWidget::attributeSetForComboBox(const std::string &attr_type, std::sh void GRPlotWidget::AttributeEditEvent() { - if (current_selection == nullptr) - { - return; - } - std::string currently_clicked_name = current_selection->get_ref()->localName(); - - QDialog dialog(this); - QString title("Selected: "); - title.append(currently_clicked_name.c_str()); - dialog.setWindowTitle(title); - auto changeParametersLabel = new QLabel("Change Parameters:"); - changeParametersLabel->setStyleSheet("font-weight: bold"); - auto form = new QFormLayout; - form->addRow(changeParametersLabel); - - QList labels; - QList fields; - QWidget *lineEdit; - std::unordered_map attr_type; - - for (const auto &cur_attr_name : current_selection->get_ref()->getAttributeNames()) - { - if (util::startsWith(cur_attr_name, "_")) - { - continue; - } - QString tooltipString = GRM::Render::getDefaultAndTooltip(current_selection->get_ref(), cur_attr_name)[1].c_str(); - tooltipString.append(". Default: "); - tooltipString.append(GRM::Render::getDefaultAndTooltip(current_selection->get_ref(), cur_attr_name)[0].c_str()); - - if (combo_box_attr.contains(cur_attr_name.c_str())) - { - lineEdit = new QComboBox(&dialog); - advancedAttributeComboBoxHandler(cur_attr_name, current_selection->get_ref()->localName(), &lineEdit); - if (current_selection->get_ref()->getAttribute(cur_attr_name).isInt()) - { - attr_type.emplace(cur_attr_name, "xs:integer"); - } - else if (current_selection->get_ref()->getAttribute(cur_attr_name).isDouble()) - { - attr_type.emplace(cur_attr_name, "xs:double"); - } - else - { - attr_type.emplace(cur_attr_name, "xs:string"); - } - ((QCheckBox *)lineEdit)->setToolTip(tooltipString); - } - else if (check_box_attr.contains(cur_attr_name.c_str())) - { - lineEdit = new QCheckBox(&dialog); - ((QCheckBox *)lineEdit)->setToolTip(tooltipString); - ((QCheckBox *)lineEdit) - ->setChecked(static_cast(current_selection->get_ref()->getAttribute(cur_attr_name)) == 1); - } - else - { - if (current_selection->get_ref()->getAttribute(cur_attr_name).isInt()) - { - attr_type.emplace(cur_attr_name, "xs:integer"); - } - else if (current_selection->get_ref()->getAttribute(cur_attr_name).isDouble()) - { - attr_type.emplace(cur_attr_name, "xs:double"); - } - else - { - attr_type.emplace(cur_attr_name, "xs:string"); - } - lineEdit = new QLineEdit(&dialog); - ((QLineEdit *)lineEdit) - ->setText(static_cast(current_selection->get_ref()->getAttribute(cur_attr_name)).c_str()); - ((QLineEdit *)lineEdit)->setToolTip(tooltipString); - } - QString text_label = QString(cur_attr_name.c_str()); - form->addRow(text_label, lineEdit); - - labels << text_label; - fields << lineEdit; - } - - if (schema_tree != nullptr) - { - std::shared_ptr element; - auto selections = schema_tree->querySelectorsAll("[name=" + currently_clicked_name + "]"); - for (const auto &selection : selections) - { - if (selection->localName() == "xs:element") element = selection->children()[0]; - } - - /* iterate through complextype elements */ - for (const auto &child : element->children()) - { - if (child->localName() == "xs:attribute") - { - auto attr_name = static_cast(child->getAttribute("name")); - if (!current_selection->get_ref()->hasAttribute(attr_name)) - { - /* attributes of an element which aren't already in the tree getting added with red text color - */ - auto type_name = static_cast(child->getAttribute("type")); - attr_type.emplace(attr_name, type_name); - QString tooltipString = - GRM::Render::getDefaultAndTooltip(current_selection->get_ref(), attr_name)[1].c_str(); - tooltipString.append(". Default: "); - tooltipString.append( - GRM::Render::getDefaultAndTooltip(current_selection->get_ref(), attr_name)[0].c_str()); - - if (combo_box_attr.contains(attr_name.c_str())) - { - lineEdit = new QComboBox(&dialog); - advancedAttributeComboBoxHandler(attr_name, current_selection->get_ref()->localName(), &lineEdit); - ((QCheckBox *)lineEdit)->setToolTip(tooltipString); - } - else if (check_box_attr.contains(attr_name.c_str())) - { - lineEdit = new QCheckBox(&dialog); - ((QCheckBox *)lineEdit)->setToolTip(tooltipString); - ((QCheckBox *)lineEdit) - ->setChecked(static_cast(current_selection->get_ref()->getAttribute(attr_name)) == 1); - } - else - { - lineEdit = new QLineEdit(&dialog); - ((QLineEdit *)lineEdit)->setToolTip(tooltipString); - ((QLineEdit *)lineEdit)->setText(""); - } - QString text_label = QString("%1").arg(attr_name.c_str()); - form->addRow(text_label, lineEdit); - - labels << text_label; - fields << lineEdit; - } - } - else if (child->localName() == "xs:attributegroup") - { - /* when an element contains one or more attributegroups all attributes from these groups must be - * added */ - std::shared_ptr group; - auto group_name = static_cast(child->getAttribute("ref")); - - if (group_name != "colorrep") - { - auto attr_group_selections = schema_tree->querySelectorsAll("[name=" + group_name + "]"); - for (const auto &selection : attr_group_selections) - { - if (selection->localName() == "xs:attributegroup") group = selection; - } - - /* iterate through attribute elements */ - for (const auto &childchild : group->children()) - { - if (childchild->localName() == "xs:attribute") - { - auto attr_name = static_cast(childchild->getAttribute("name")); - if (!current_selection->get_ref()->hasAttribute(attr_name)) - { - /* attributes of an element which aren't already in the tree getting added with - * red text color */ - auto type_name = static_cast(childchild->getAttribute("type")); - attr_type.emplace(attr_name, type_name); - QString tooltipString = - GRM::Render::getDefaultAndTooltip(current_selection->get_ref(), attr_name)[1].c_str(); - tooltipString.append(". Default: "); - tooltipString.append( - GRM::Render::getDefaultAndTooltip(current_selection->get_ref(), attr_name)[0] - .c_str()); - - if (combo_box_attr.contains(attr_name.c_str())) - { - lineEdit = new QComboBox(&dialog); - advancedAttributeComboBoxHandler(attr_name, current_selection->get_ref()->localName(), - &lineEdit); - ((QCheckBox *)lineEdit)->setToolTip(tooltipString); - } - else if (check_box_attr.contains(attr_name.c_str())) - { - lineEdit = new QCheckBox(&dialog); - ((QCheckBox *)lineEdit)->setToolTip(tooltipString); - ((QCheckBox *)lineEdit) - ->setChecked( - static_cast(current_selection->get_ref()->getAttribute(attr_name)) == 1); - } - else - { - lineEdit = new QLineEdit(&dialog); - ((QLineEdit *)lineEdit)->setToolTip(tooltipString); - ((QLineEdit *)lineEdit)->setText(""); - } - QString text_label = - QString("%1").arg(attr_name.c_str()); - form->addRow(text_label, lineEdit); - - labels << text_label; - fields << lineEdit; - } - } - } - } - else - { - /* special case for colorrep cause there are way to many attributes inside the attributegroup - */ - lineEdit = new QLineEdit(&dialog); - ((QLineEdit *)lineEdit)->setText(""); - QString text_label = QString("%1").arg("Colorrep-index"); - form->addRow(text_label, lineEdit); - - attr_type.emplace("Colorrep-index", "xs:string"); - labels << text_label; - fields << lineEdit; - - lineEdit = new QLineEdit(&dialog); - ((QLineEdit *)lineEdit)->setText(""); - text_label = QString("%1").arg("Colorrep-value"); - form->addRow(text_label, lineEdit); - - attr_type.emplace("Colorrep-value", "xs:string"); - labels << text_label; - fields << lineEdit; - } - } - } - } - - QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog); - form->addRow(&buttonBox); - QObject::connect(&buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept())); - QObject::connect(&buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject())); - - auto scrollAreaContent = new QWidget; - scrollAreaContent->setLayout(form); - auto scrollArea = new QScrollArea; - scrollArea = new QScrollArea; - scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - scrollArea->setWidgetResizable(true); - scrollArea->setWidget(scrollAreaContent); - - auto groupBoxLayout = new QVBoxLayout; - groupBoxLayout->addWidget(scrollArea); - dialog.setLayout(groupBoxLayout); - - if (dialog.exec() == QDialog::Accepted) - { - for (int i = 0; i < labels.count(); i++) - { - qDebug() << typeid(fields[i]).name(); - auto &field = *fields[i]; // because typeid(*fields[i]) is bad :( - if (util::startsWith(labels[i].toStdString(), "") && - util::endsWith(labels[i].toStdString(), "")) - { - labels[i].remove(0, 29); - labels[i].remove(labels[i].size() - 7, 7); - } - std::string attr_name = labels[i].toStdString(); - if (typeid(field) == typeid(QLineEdit) && ((QLineEdit *)fields[i])->isModified()) - { - std::string name = std::string(current_selection->get_ref()->getAttribute("name")); - if (((QLineEdit *)fields[i])->text().toStdString().empty()) - { - /* remove attributes from tree when the value got removed */ - current_selection->get_ref()->removeAttribute(labels[i].toStdString()); - } - else - { - if (labels[i].toStdString() == "text") - { - const std::string value = ((QLineEdit *)fields[i])->text().toStdString(); - if (attr_type[attr_name] == "xs:string" || - (attr_type[attr_name] == "strint" && !util::is_digits(value))) - { - if (current_selection->get_ref()->parentElement()->localName() == "text_region") - { - current_selection->get_ref()->parentElement()->parentElement()->setAttribute( - "text_content", value); - } - else if (name == "xlabel" || name == "ylabel") - { - current_selection->get_ref() - ->parentElement() - ->parentElement() - ->querySelectors(name) - ->setAttribute(name, value); - } - } - else if (attr_type[attr_name] == "xs:double") - { - current_selection->get_ref()->parentElement()->setAttribute(labels[i].toStdString(), - std::stod(value)); - } - else if (attr_type[attr_name] == "xs:integer" || - (attr_type[attr_name] == "strint" && util::is_digits(value))) - { - current_selection->get_ref()->parentElement()->setAttribute(labels[i].toStdString(), - std::stoi(value)); - } - } - if (labels[i].toStdString() == "Colorrep-index") - { - /* special case for colorrep attribute */ - current_selection->get_ref()->setAttribute("colorrep." + - ((QLineEdit *)fields[i])->text().toStdString(), - ((QLineEdit *)fields[i + 1])->text().toStdString()); - } - else if (labels[i].toStdString() != "Colorrep-value") - { - const std::string value = ((QLineEdit *)fields[i])->text().toStdString(); - if (attr_type[attr_name] == "xs:string" || - (attr_type[attr_name] == "strint" && !util::is_digits(value))) - { - current_selection->get_ref()->setAttribute(labels[i].toStdString(), value); - } - else if (attr_type[attr_name] == "xs:double") - { - current_selection->get_ref()->setAttribute(labels[i].toStdString(), std::stod(value)); - } - else if (attr_type[attr_name] == "xs:integer" || - (attr_type[attr_name] == "strint" && util::is_digits(value))) - { - current_selection->get_ref()->setAttribute(labels[i].toStdString(), std::stoi(value)); - } - } - } - } - else if (typeid(field) == typeid(QComboBox)) - { - int index = ((QComboBox *)fields[i])->currentIndex(); - if (((QComboBox *)fields[i])->itemText(index).toStdString().empty()) - { - /* remove attributes from tree when the value got removed */ - current_selection->get_ref()->removeAttribute(labels[i].toStdString()); - } - else - { - const std::string value = ((QComboBox *)fields[i])->itemText(index).toStdString(); - attributeSetForComboBox(attr_type[attr_name], current_selection->get_ref(), value, - (labels[i]).toStdString()); - } - } - else if (typeid(field) == typeid(QCheckBox)) - { - current_selection->get_ref()->setAttribute(labels[i].toStdString(), - ((QCheckBox *)fields[i])->isChecked()); - } - } - current_selection = nullptr; - mouse_move_selection = nullptr; - amount_scrolled = 0; - tree_update = true; - clicked.clear(); - if (getenv("GRM_DEBUG")) - { - std::cerr << toXML(grm_get_document_root(), - GRM::SerializerOptions{std::string(2, ' '), - GRM::SerializerOptions::InternalAttributesFormat::Plain}) - << "\n"; - } - reset_pixmap(); - } - else - { - tree_update = false; - } + edit_element_widget->show(); + edit_element_widget->AttributeEditEvent(); } void GRPlotWidget::draw() @@ -1261,7 +988,7 @@ void GRPlotWidget::draw() if (global_root == nullptr) global_root = grm_get_document_root(); auto plot_elem = global_root->querySelectors("plot"); - auto kind = static_cast(plot_elem->getAttribute("kind")); + auto kind = static_cast(plot_elem->getAttribute("_kind")); snprintf(file, 50, "grplot_%s.%s", kind.c_str(), file_export.c_str()); grm_export(file); } @@ -1351,6 +1078,12 @@ static const std::string accumulatedTooltipTemplate{"\ void GRPlotWidget::paintEvent(QPaintEvent *event) { + if (getenv("GRDISPLAY") && strcmp(getenv("GRDISPLAY"), "edit") == 0) + { + if (!table_widget->isVisible() && show_context_action->isChecked()) show_context_action->setChecked(false); + if (!treewidget->isVisible() && show_container_action->isChecked()) show_container_action->setChecked(false); + if (!add_element_widget->isVisible() && add_element_action->isChecked()) add_element_action->setChecked(false); + } util::unused(event); paint(this); } @@ -1457,7 +1190,7 @@ void GRPlotWidget::paint(QPaintDevice *paint_device) label.setHtml(QString::fromStdString(info)); if (global_root == nullptr) global_root = grm_get_document_root(); auto plot_elem = global_root->querySelectors("plot"); - kind = static_cast(plot_elem->getAttribute("kind")); + kind = static_cast(plot_elem->getAttribute("_kind")); if (kind == "heatmap" || kind == "marginal_heatmap") { background.setAlpha(224); @@ -1716,7 +1449,7 @@ void GRPlotWidget::mouseMoveEvent(QMouseEvent *event) auto plot_elem = global_root->querySelectors("plot"); if (plot_elem) { - kind = static_cast(plot_elem->getAttribute("kind")); + kind = static_cast(plot_elem->getAttribute("_kind")); if (kind == "marginal_heatmap") { grm_args_t *input_args; @@ -2323,6 +2056,12 @@ void GRPlotWidget::hist() series_elem->setAttribute("kind", "hist"); } } + + // to get the same bars then before all bars have to exist during render call so that the linespec work properly + for (const auto &elem : global_root->querySelectorsAll("series_hist")) + { + elem->setAttribute("_update_required", true); + } redraw(); } @@ -2338,6 +2077,13 @@ void GRPlotWidget::barplot() series_elem->setAttribute("kind", "barplot"); } } + + // to get the same bars then before all bars have to exist during render call so that the linespec work properly + for (const auto &elem : global_root->querySelectorsAll("series_barplot")) + { + elem->removeAttribute("fill_color_ind"); + elem->setAttribute("_update_required", true); + } redraw(); } @@ -2353,6 +2099,12 @@ void GRPlotWidget::stairs() series_elem->setAttribute("kind", "stairs"); } } + + // to get the same lines then before all lines have to exist during render call so that the linespec work properly + for (const auto &elem : global_root->querySelectorsAll("series_stairs")) + { + elem->setAttribute("_update_required", true); + } redraw(); } @@ -2391,6 +2143,26 @@ void GRPlotWidget::hexbin() redraw(); } +void GRPlotWidget::polar_line() +{ + if (global_root == nullptr) global_root = grm_get_document_root(); + for (const auto &elem : global_root->querySelectorsAll("series_polar_scatter")) + { + elem->setAttribute("kind", "polar_line"); + } + redraw(); +} + +void GRPlotWidget::polar_scatter() +{ + auto root = grm_get_document_root(); + for (const auto &elem : root->querySelectorsAll("series_polar_line")) + { + elem->setAttribute("kind", "polar_scatter"); + } + redraw(); +} + void GRPlotWidget::pdf() { file_export = "pdf"; @@ -2449,7 +2221,7 @@ void GRPlotWidget::extract_bounding_boxes_from_grm(QPainter &painter) if (xmin == DBL_MAX || xmax == -DBL_MAX || ymin == DBL_MAX || ymax == -DBL_MAX) { - qDebug() << "skipping" << cur_child->localName().c_str(); + if (getenv("GRM_DEBUG")) qDebug() << "skipping" << cur_child->localName().c_str(); } else { @@ -2515,6 +2287,23 @@ void GRPlotWidget::highlight_current_selection(QPainter &painter) } painter.fillRect(rect, QBrush(QColor(255, 0, 0, 30), Qt::SolidPattern)); } + if (!referenced_elements.empty()) + { + for (const auto &elem : referenced_elements) + { + auto rect = elem.boundingRect(); + if (elem.get_ref() != nullptr) + { + auto bbox_xmin = static_cast(elem.get_ref()->getAttribute("_bbox_x_min")); + auto bbox_xmax = static_cast(elem.get_ref()->getAttribute("_bbox_x_max")); + auto bbox_ymin = static_cast(elem.get_ref()->getAttribute("_bbox_y_min")); + auto bbox_ymax = static_cast(elem.get_ref()->getAttribute("_bbox_y_max")); + rect = QRectF(bbox_xmin, bbox_ymin, bbox_xmax - bbox_xmin, bbox_ymax - bbox_ymin); + painter.drawText(rect.topLeft() + QPointF(5, 10), elem.get_ref()->localName().c_str()); + } + painter.fillRect(rect, QBrush(QColor(243, 224, 59, 40), Qt::SolidPattern)); + } + } } } @@ -2572,6 +2361,7 @@ void GRPlotWidget::load_file_slot() grm_load_graphics_tree(file); global_root = grm_get_document_root(); redraw(); + if (table_widget->isVisible()) table_widget->updateData(grm_get_render()->getContext()); #else std::stringstream text_stream; text_stream << "XML support not compiled in. Please recompile GRPlot with libxml2 support."; @@ -2736,6 +2526,136 @@ void GRPlotWidget::screenChanged() redraw(); } +void GRPlotWidget::showContextSlot() +{ + if (show_context_action->isChecked()) + { + auto context = grm_get_render()->getContext(); + table_widget->updateData(context); + table_widget->show(); + } + else + { + table_widget->hide(); + } + table_widget->resize(width(), 350); + table_widget->move((int)(this->pos().x() + 0.5 * this->width() - 61), + this->pos().y() - 28 + table_widget->geometry().y()); +} + +void GRPlotWidget::addContextSlot() +{ + std::string path = + QFileDialog::getOpenFileName(this, "Open column data file", QDir::homePath(), "(*.dat *.csv *.xyz)") + .toStdString(); + if (path.empty()) return; + + // convert the data + if (!grm_context_data_from_file(grm_get_render()->getContext(), path)) + { + fprintf(stderr, "Could not interpret the file to context data\n"); + return; + } + auto context = grm_get_render()->getContext(); + table_widget->updateData(context); +} + +void GRPlotWidget::addGRPlotDataContextSlot() +{ + std::string path = + QFileDialog::getOpenFileName(this, "Interpret matrix as 1 column data", QDir::homePath(), "(*.dat *.csv *.xyz)") + .toStdString(); + if (path.empty()) return; + + // convert the data + if (!grm_context_data_from_file(grm_get_render()->getContext(), path, true)) + { + fprintf(stderr, "Could not interpret the file to context data\n"); + return; + } + auto context = grm_get_render()->getContext(); + table_widget->updateData(context); +} + +void GRPlotWidget::generateLinearContextSlot() +{ + QList fields; + std::vector label = {"Context-Data key:", "Min value:", "Max value", "Number of data"}; + QDialog dialog(this); + QString title("Generate linear context entry"); + dialog.setWindowTitle(title); + auto form = new QFormLayout; + + // needed information to generate linear data for the context + for (int i = 0; i < 4; i++) + { + auto lineEdit = new QLineEdit(&dialog); + ((QLineEdit *)lineEdit)->setText(""); + auto text_label = QString(label[i].c_str()); + form->addRow(text_label, lineEdit); + fields << lineEdit; + } + + QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog); + form->addRow(&buttonBox); + QObject::connect(&buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept())); + QObject::connect(&buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject())); + + auto scrollAreaContent = new QWidget; + scrollAreaContent->setLayout(form); + auto scrollArea = new QScrollArea; + scrollArea = new QScrollArea; + scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + scrollArea->setWidgetResizable(true); + scrollArea->setWidget(scrollAreaContent); + + auto groupBoxLayout = new QVBoxLayout; + groupBoxLayout->addWidget(scrollArea); + dialog.setLayout(groupBoxLayout); + + if (dialog.exec() == QDialog::Accepted) + { + int n; + double start, end; + std::vector values; + std::vector data_vec; + std::shared_ptr context = grm_get_render()->getContext(); + + for (int i = 0; i < 4; i++) + { + auto &field = *fields[i]; + auto value = ((QLineEdit *)fields[i])->text().toStdString(); + if (value.empty()) + { + fprintf(stderr, "All fields must be filled to generate linear context data\n"); + return; + } + values.push_back(value); + } + + // convert entries into linear data vec + try + { + start = std::stod(values[1]); + end = std::stod(values[2]); + n = std::stoi(values[3]); + for (int i = 0; i < n; i++) + { + data_vec.push_back(start + i * (end - start) / (n - 1)); + } + + (*context)[values[0]] = data_vec; + table_widget->updateData(context); + } + catch (std::invalid_argument &e) + { + fprintf(stderr, "Invalid argument for generate linear context parameter\n"); + return; + } + } +} + void GRPlotWidget::size_callback(const grm_event_t *new_size_object) { // TODO: Get Plot ID @@ -2794,8 +2714,9 @@ void GRPlotWidget::processTestCommandsFile() { elem->setAttribute(words[n - 2].toUtf8().constData(), words[n - 1].toUtf8().constData()); } + auto value = words[n - 1].toUtf8().constData(); - if (strcmp(words[n - 1].toUtf8().constData(), "line") == 0) + if (strcmp(value, "line") == 0) { // to get the same lines then before all lines have to exist during render call so that the linespec // work properly @@ -2804,6 +2725,16 @@ void GRPlotWidget::processTestCommandsFile() elem->setAttribute("_update_required", true); } } + if (strcmp(value, "barplot") == 0 || strcmp(value, "hist") == 0 || strcmp(value, "stairs") == 0) + { + // to get the same barplots then before all lines have to exist during render call so that the + // linespec work properly + for (const auto &elem : global_root->querySelectorsAll("series_" + std::string(value))) + { + if (strcmp(value, "barplot") == 0) elem->removeAttribute("fill_color_ind"); + elem->setAttribute("_update_required", true); + } + } redraw(); } else if (words[0] == "mouseMoveEvent" && words.size() == 3) @@ -3039,9 +2970,9 @@ void GRPlotWidget::set_current_selection(Bounding_object *p_current_selection) this->current_selection = p_current_selection; } -Bounding_object *GRPlotWidget::get_current_selection() +Bounding_object **GRPlotWidget::get_current_selection() { - return this->current_selection; + return &(this->current_selection); } QStringList GRPlotWidget::getCheckBoxAttributes() @@ -3069,3 +3000,22 @@ const std::list> &GRPlotWidget::get_current_sel { return current_selections; } + +void GRPlotWidget::setTreeUpdate(bool status) +{ + this->tree_update = status; +} + +void GRPlotWidget::editElementAccepted() +{ + current_selection = nullptr; + mouse_move_selection = nullptr; + amount_scrolled = 0; + clicked.clear(); + reset_pixmap(); +} + +void GRPlotWidget::set_referenced_elements(std::vector referenced_elements) +{ + this->referenced_elements = referenced_elements; +} diff --git a/lib/grm/grplot/grplot_widget.hxx b/lib/grm/grplot/grplot_widget.hxx index 3b6256a4a..b9ede474b 100644 --- a/lib/grm/grplot/grplot_widget.hxx +++ b/lib/grm/grplot/grplot_widget.hxx @@ -17,6 +17,8 @@ class GRPlotWidget; #include "gredit/TreeWidget.h" #include "gredit/AddElementWidget.h" +#include "gredit/EditElementWidget.h" +#include "gredit/TableWidget.h" #include "qtterm/receiver_thread.h" #include "qtterm/grm_args_t_wrapper.h" #include "util.hxx" @@ -39,7 +41,7 @@ public: void set_selected_parent(Bounding_object *parent); Bounding_object *get_selected_parent(); void set_current_selection(Bounding_object *current_selection); - Bounding_object *get_current_selection(); + Bounding_object **get_current_selection(); void add_current_selection(std::unique_ptr current_selection); std::list>::iterator erase_current_selection(std::list>::const_iterator current_selection); @@ -50,6 +52,11 @@ public: QStringList getComboBoxAttributes(); void attributeSetForComboBox(const std::string &attr_type, std::shared_ptr element, const std::string &value, const std::string &label); + void advancedAttributeComboBoxHandler(const std::string &cur_attr_name, std::string cur_elem_name, + QWidget **lineEdit); + void setTreeUpdate(bool status); + void editElementAccepted(); + void set_referenced_elements(std::vector referenced_elements); protected: virtual void draw(); @@ -96,6 +103,8 @@ private slots: void stem(); void shade(); void hexbin(); + void polar_line(); + void polar_scatter(); void pdf(); void png(); void jpeg(); @@ -109,6 +118,10 @@ private slots: void add_element_slot(); void received(grm_args_t_wrapper args); void screenChanged(); + void showContextSlot(); + void addContextSlot(); + void addGRPlotDataContextSlot(); + void generateLinearContextSlot(); private: struct MouseState @@ -199,7 +212,7 @@ private: std::vector tooltips; QTextDocument label; Bounding_logic *bounding_logic; - std::vector clicked; + std::vector clicked, referenced_elements; Bounding_object *current_selection, *mouse_move_selection, *selected_parent; std::list> current_selections; bool highlightBoundingObjects; @@ -212,10 +225,12 @@ private: bool tree_update = true; QSize size_hint; QStringList check_box_attr, combo_box_attr; + TableWidget *table_widget; + EditElementWidget *edit_element_widget; QMenuBar *menu; QMenu *type, *algo, *export_menu, *editor_menu, *modi_menu; - QMenu *file_menu, *configuration_menu; + QMenu *file_menu, *configuration_menu, *context_menu, *add_context_data; QAction *marginalheatmapAllAct, *marginalheatmapLineAct; QAction *sumAct, *maxAct; QAction *lineAct, *scatterAct; @@ -224,10 +239,12 @@ private: QAction *plot3Act, *trisurfAct, *tricontAct, *scatter3Act; QAction *histAct, *barplotAct, *stairsAct, *stemAct; QAction *shadeAct, *hexbinAct; + QAction *polarLineAct, *polarScatterAct; QAction *PdfAct, *PngAct, *JpegAct, *SvgAct; QAction *show_container_action, *show_bounding_boxes_action, *save_file_action, *load_file_action, *editor_action, *add_element_action; QAction *moveableModeAct; + QAction *show_context_action, *add_context_action, *generate_linear_context_action, *add_grplot_data_context; QCursor *csr; void reset_pixmap(); @@ -239,8 +256,6 @@ private: QSize sizeHint() const override; void size_callback(const grm_event_t *); void cmd_callback(const grm_request_event_t *); - void advancedAttributeComboBoxHandler(const std::string &cur_attr_name, std::string cur_elem_name, - QWidget **lineEdit); }; #endif /* ifndef GRPLOT_WIDGET_H_INCLUDED */ diff --git a/lib/grm/grplot/makefile.mingw b/lib/grm/grplot/makefile.mingw index 83ac82951..4160b60a9 100644 --- a/lib/grm/grplot/makefile.mingw +++ b/lib/grm/grplot/makefile.mingw @@ -28,7 +28,7 @@ ifeq ($(ARCHITECTURE),i686) grplot.exe: grplot.cxx $(CXX) -o $@ $^ else -grplot.exe: grplot.cxx grplot_mainwindow.cxx grplot_widget.cxx util.cxx gredit/AddElementWidget.cpp gredit/Bounding_logic.cpp gredit/Bounding_object.cpp gredit/CustomTreeWidgetItem.cpp gredit/TreeWidget.cpp qtterm/grm_args_t_wrapper.cpp qtterm/receiver_thread.cpp $(GRMLIB) +grplot.exe: grplot.cxx grplot_mainwindow.cxx grplot_widget.cxx util.cxx gredit/AddElementWidget.cpp gredit/Bounding_logic.cpp gredit/Bounding_object.cpp gredit/CustomTreeWidgetItem.cpp gredit/EditElementWidget.cpp gredit/TableWidget.cpp gredit/TreeWidget.cpp qtterm/grm_args_t_wrapper.cpp qtterm/receiver_thread.cpp $(GRMLIB) wget https://gr-framework.org/downloads/3rdparty/qt5-runtime-Windows-$(ARCHITECTURE)-mingw81.tar.gz tar xzf qt5-runtime-Windows-$(ARCHITECTURE)-mingw81.tar.gz moc -DGRDIR=\"$(GRDIR)\" -Iinclude grplot_widget.hxx -o moc_grplot_widget.cxx @@ -37,10 +37,12 @@ grplot.exe: grplot.cxx grplot_mainwindow.cxx grplot_widget.cxx util.cxx gredit/A moc -DGRDIR=\"$(GRDIR)\" -Iinclude gredit/Bounding_logic.h -o gredit/moc_Bounding_logic.cpp moc -DGRDIR=\"$(GRDIR)\" -Iinclude gredit/Bounding_object.h -o gredit/moc_Bounding_object.cpp moc -DGRDIR=\"$(GRDIR)\" -Iinclude gredit/CustomTreeWidgetItem.h -o gredit/moc_CustomTreeWidgetItem.cpp + moc -DGRDIR=\"$(GRDIR)\" -Iinclude gredit/EditElementWidget.h -o gredit/moc_EditElementWidget.cpp + moc -DGRDIR=\"$(GRDIR)\" -Iinclude gredit/TableWidget.h -o gredit/moc_TableWidget.cpp moc -DGRDIR=\"$(GRDIR)\" -Iinclude gredit/TreeWidget.h -o gredit/moc_TreeWidget.cpp moc -DGRDIR=\"$(GRDIR)\" -Iinclude qtterm/grm_args_t_wrapper.h -o qtterm/moc_grm_args_t_wrapper.cpp moc -DGRDIR=\"$(GRDIR)\" -Iinclude qtterm/receiver_thread.h -o qtterm/moc_receiver_thread.cpp - $(CXX) -Wl,--subsystem,console -mconsole -std=c++17 -DGRDIR=\"$(GRDIR)\" -DGR_STATIC_LIB $(INCLUDES) -Iinclude -Iinclude/QtGui -Iinclude/QtWidgets -Iinclude/QtCore -I../ -o $@ $^ moc_grplot_widget.cxx moc_grplot_mainwindow.cxx gredit/moc_AddElementWidget.cpp gredit/moc_Bounding_logic.cpp gredit/moc_Bounding_object.cpp gredit/moc_CustomTreeWidgetItem.cpp gredit/moc_TreeWidget.cpp qtterm/moc_grm_args_t_wrapper.cpp qtterm/moc_receiver_thread.cpp Qt5Gui.dll Qt5Widgets.dll Qt5Core.dll \ + $(CXX) -Wl,--subsystem,console -mconsole -std=c++17 -DGRDIR=\"$(GRDIR)\" -DGR_STATIC_LIB $(INCLUDES) -Iinclude -Iinclude/QtGui -Iinclude/QtWidgets -Iinclude/QtCore -I../ -o $@ $^ moc_grplot_widget.cxx moc_grplot_mainwindow.cxx gredit/moc_AddElementWidget.cpp gredit/moc_Bounding_logic.cpp gredit/moc_Bounding_object.cpp gredit/moc_CustomTreeWidgetItem.cpp gredit/moc_EditElementWidget.cpp gredit/moc_TableWidget.cpp gredit/moc_TreeWidget.cpp qtterm/moc_grm_args_t_wrapper.cpp qtterm/moc_receiver_thread.cpp Qt5Gui.dll Qt5Widgets.dll Qt5Core.dll \ $(XERCESCLIBS) $(JPEGLIBS) $(FTLIBS) $(PNGLIBS) $(ZLIBS) $(QHLIBS) $(LIBS) endif diff --git a/lib/grm/include/grm/dom_render/InvalidValueError.hxx b/lib/grm/include/grm/dom_render/InvalidValueError.hxx new file mode 100644 index 000000000..e899165e3 --- /dev/null +++ b/lib/grm/include/grm/dom_render/InvalidValueError.hxx @@ -0,0 +1,13 @@ +#ifndef GRENDER_INVALIDVALUEERROR_HXX +#define GRENDER_INVALIDVALUEERROR_HXX + +#include +#include + +class InvalidValueError : public std::logic_error +{ +public: + EXPORT explicit InvalidValueError(const std::string &what_arg) : std::logic_error(what_arg) {} +}; + +#endif // GRENDER_INVALIDVALUEERROR_HXX diff --git a/lib/grm/include/grm/dom_render/context.hxx b/lib/grm/include/grm/dom_render/context.hxx index df51c1409..2689e5040 100644 --- a/lib/grm/include/grm/dom_render/context.hxx +++ b/lib/grm/include/grm/dom_render/context.hxx @@ -46,9 +46,6 @@ public: private: Context *context; std::string key; - bool intUsed(); - bool doubleUsed(); - bool stringUsed(); void increment_key(const std::string &); public: @@ -77,6 +74,9 @@ public: explicit operator std::vector *(); explicit operator const std::vector *() const; + bool intUsed(); + bool doubleUsed(); + bool stringUsed(); void delete_key(const std::string &); void use_context_key(const std::string &key, const std::string &old_key = ""); void decrement_key(const std::string &); diff --git a/lib/grm/include/grm/dom_render/render.hxx b/lib/grm/include/grm/dom_render/render.hxx index 6ff4cef09..a5b28abae 100644 --- a/lib/grm/include/grm/dom_render/render.hxx +++ b/lib/grm/include/grm/dom_render/render.hxx @@ -23,10 +23,10 @@ #define PLOT_DEFAULT_CLEAR 1 #define PLOT_DEFAULT_UPDATE 1 #define PLOT_DEFAULT_LOCATION 1 -#define PLOT_DEFAULT_SUBPLOT_MIN_X 0.0 -#define PLOT_DEFAULT_SUBPLOT_MAX_X 1.0 -#define PLOT_DEFAULT_SUBPLOT_MIN_Y 0.0 -#define PLOT_DEFAULT_SUBPLOT_MAX_Y 1.0 +#define PLOT_DEFAULT_PLOT_MIN_X 0.0 +#define PLOT_DEFAULT_PLOT_MAX_X 1.0 +#define PLOT_DEFAULT_PLOT_MIN_Y 0.0 +#define PLOT_DEFAULT_PLOT_MAX_Y 1.0 #define PLOT_DEFAULT_ROTATION 40.0 #define PLOT_DEFAULT_TILT 60.0 #define PLOT_DEFAULT_KEEP_ASPECT_RATIO 1 @@ -80,10 +80,12 @@ #define PLOT_2D_CHAR_HEIGHT 0.018 #define PLOT_POLAR_CHAR_HEIGHT 0.018 #define PLOT_DEFAULT_AXES_TICK_SIZE 0.0075 -#define DEFAULT_ASPECT_RATIO_FOR_SCALING 4.0 / 3.0 +#define DEFAULT_ASPECT_RATIO_FOR_SCALING (4.0 / 3.0) #define PLOT_DEFAULT_ONLY_QUADRATIC_ASPECT_RATIO 0 #define MIRRORED_AXIS_DEFAULT 1 #define SCIENTIFIC_FORMAT_OPTION 2 +#define PLOT_DEFAULT_MODEL 0 +#define ERRORBAR_DEFAULT_STYLE 0 /* ~~~~~~~~~~~~~~~~~~~~~~~~~ util ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ @@ -125,6 +127,9 @@ EXPORT int textAlignHorizontalStringToInt(const std::string &text_align_horizont EXPORT int textAlignVerticalStringToInt(const std::string &text_align_vertical_str); EXPORT int textEncodingStringToInt(const std::string &text_encoding_str); EXPORT int tickOrientationStringToInt(const std::string &tick_orientation_str); +EXPORT int errorBarStyleStringToInt(const std::string &error_bar_stylr_str); +EXPORT int clipRegionStringToInt(const std::string &error_bar_stylr_str); +EXPORT int resampleMethodStringToInt(const std::string &error_bar_stylr_str); EXPORT std::string algorithmIntToString(int algorithm); EXPORT std::string colormapIntToString(int colormap); @@ -142,6 +147,9 @@ EXPORT std::string textAlignHorizontalIntToString(int text_align_horizontal); EXPORT std::string textAlignVerticalIntToString(int text_align_vertical); EXPORT std::string textEncodingIntToString(int text_encoding); EXPORT std::string tickOrientationIntToString(int tick_orientation); +EXPORT std::string errorBarStyleIntToString(int error_bar_style); +EXPORT std::string clipRegionIntToString(int error_bar_style); +EXPORT std::string resampleMethodIntToString(int error_bar_style); EXPORT std::vector getSizeUnits(); EXPORT std::vector getColormaps(); @@ -154,6 +162,9 @@ EXPORT std::vector getTextAlignHorizontal(); EXPORT std::vector getTextAlignVertical(); EXPORT std::vector getAlgorithm(); EXPORT std::vector getModel(); +EXPORT std::vector getContextAttributes(); + +EXPORT void addValidContextKey(std::string key); /* ========================= classes ================================================================================ */ @@ -253,7 +264,7 @@ public: int tick_orientation, double label_pos, const std::shared_ptr &ext_element = nullptr); - std::shared_ptr createTickGroup(int is_major, std::string tick_label, double value, double width, + std::shared_ptr createTickGroup(int is_major, const std::string &tick_label, double value, double width, const std::shared_ptr &ext_element = nullptr); std::shared_ptr createTick(int is_major, double value, @@ -267,10 +278,6 @@ public: const std::shared_ptr &extContext = nullptr, const std::shared_ptr &extElement = nullptr); - std::shared_ptr createDrawPolarAxes(int angle_ticks, const std::string &kind, int phiflip, - const std::string &norm = "", double tick = 0.0, double line_width = 0.0, - const std::shared_ptr &extElement = nullptr); - std::shared_ptr createPieLegend(const std::string &labels_key, std::optional> labels, const std::shared_ptr &extContext = nullptr, @@ -386,13 +393,22 @@ public: std::shared_ptr createIntegral(double int_lim_low, double int_lim_high, const std::shared_ptr &extElement = nullptr); - std::shared_ptr createSideRegion(std::string location, + std::shared_ptr createSideRegion(const std::string &location, const std::shared_ptr &ext_element = nullptr); std::shared_ptr createTextRegion(const std::shared_ptr &ext_element = nullptr); std::shared_ptr createSidePlotRegion(const std::shared_ptr &ext_element = nullptr); + std::shared_ptr createRhoAxes(const std::shared_ptr &ext_element = nullptr); + + std::shared_ptr createThetaAxes(const std::shared_ptr &ext_element = nullptr); + + std::shared_ptr createAngleLine(double x, double y, const std::string &angle_label, + const std::shared_ptr &ext_element = nullptr); + + std::shared_ptr createArcGridLine(double value, const std::shared_ptr &ext_element = nullptr); + //! Modifierfunctions /* ------------------------------- setter functions ----------------------------------------------------------------*/ @@ -411,6 +427,8 @@ public: //! Use Fallback void setNextColor(const std::shared_ptr &element); + void setClipRegion(const std::shared_ptr &element, int region); + void setViewport(const std::shared_ptr &element, double xmin, double xmax, double ymin, double ymax); void setWSViewport(const std::shared_ptr &element, double xmin, double xmax, double ymin, double ymax); @@ -494,7 +512,7 @@ public: void setProjectionType(const std::shared_ptr &element, int type); - void setSubplot(const std::shared_ptr &element, double xmin, double xmax, double ymin, double ymax); + void setPlot(const std::shared_ptr &element, double xmin, double xmax, double ymin, double ymax); void setOriginPosition(const std::shared_ptr &element, const std::string &x_org_pos, const std::string &y_org_pos); diff --git a/lib/grm/include/grm/import.h b/lib/grm/include/grm/import.h index a9fcefddd..94136eb4f 100644 --- a/lib/grm/include/grm/import.h +++ b/lib/grm/include/grm/import.h @@ -32,5 +32,7 @@ EXPORT int grm_plot_from_file(int argc, char **argv); #ifdef __cplusplus } +EXPORT int grm_context_data_from_file(const std::shared_ptr &context, const std::string &path, + bool interpret_matrix_as_one_column = false); #endif #endif // GRM_IMPORT_H_INCLUDED diff --git a/lib/grm/include/grm/layout.hxx b/lib/grm/include/grm/layout.hxx index 2140224e5..ec07e5c78 100644 --- a/lib/grm/include/grm/layout.hxx +++ b/lib/grm/include/grm/layout.hxx @@ -21,10 +21,10 @@ public: bool isPositive(); bool isForward(); - int rowStart; - int rowStop; - int colStart; - int colStop; + int row_start; + int row_stop; + int col_start; + int col_stop; friend class Grid; }; @@ -35,9 +35,9 @@ public: GridElement(double absHeight, double absWidth, int absHeightPxl, int absWidthPxl, int fitParentsHeight, int fitParentsWidth, double relativeHeight, double relativeWidth, double aspectRatio); virtual ~GridElement(); - virtual void finalizeSubplot(); + virtual void finalizePlot(); virtual bool isGrid(); - void setSubplot(double x1, double x2, double y1, double y2); + void setPlot(double x1, double x2, double y1, double y2); void setAbsHeight(double height); void setAbsHeightPxl(int height); void setRelativeHeight(double height); @@ -47,31 +47,31 @@ public: void setAspectRatio(double ar); void setFitParentsHeight(bool fitParentsHeight); void setFitParentsWidth(bool fitParentsWidth); - double *getSubplot(); - grm_args_t *subplot_args = nullptr; - - double *subplot; - - double absHeight = -1; - double absWidth = -1; - int absHeightPxl = -1; - int absWidthPxl = -1; - int fitParentsHeight = 0; - int fitParentsWidth = 1; - double relativeHeight = -1; - double relativeWidth = -1; - double aspectRatio = -1; - - int widthSet = 0; - int heightSet = 0; - int arSet = 0; - int subplotSet = 0; + double *getPlot(); + grm_args_t *plot_args = nullptr; + + double *plot; + + double abs_height = -1; + double abs_width = -1; + int abs_height_pxl = -1; + int abs_width_pxl = -1; + int fit_parents_height = 0; + int fit_parents_width = 1; + double relative_height = -1; + double relative_width = -1; + double aspect_ratio = -1; + + int width_set = 0; + int height_set = 0; + int ar_set = 0; + int plot_set = 0; int finalized = 0; friend class Grid; - std::shared_ptr elementInDOM = nullptr; + std::shared_ptr element_in_dom = nullptr; }; class EXPORT Grid : public GridElement @@ -90,7 +90,7 @@ public: void ensureCellsAreGrid(Slice *slice); GridElement *getElement(int row, int col) const; void printGrid() const; - virtual void finalizeSubplot() override; + virtual void finalizePlot() override; bool isGrid() override; void trim(); int getColSpan(GridElement *element); diff --git a/lib/grm/include/grm/plot.h b/lib/grm/include/grm/plot.h index ca7b3158e..f16599de9 100644 --- a/lib/grm/include/grm/plot.h +++ b/lib/grm/include/grm/plot.h @@ -65,6 +65,7 @@ EXPORT int get_focus_and_factor_from_dom(const int x1, const int y1, const int x const int keep_aspect_ratio, double *factor_x, double *factor_y, double *focus_x, double *focus_y, std::shared_ptr &subplot_element); +EXPORT std::map> grm_get_context_data(); #if !defined(NO_XERCES_C) EXPORT std::shared_ptr grm_load_graphics_tree_schema(bool with_private_attributes = false); diff --git a/lib/grm/src/grm/dom_render/graphics_tree/private_schema.xsd b/lib/grm/src/grm/dom_render/graphics_tree/private_schema.xsd index 10ba424bd..677b05261 100644 --- a/lib/grm/src/grm/dom_render/graphics_tree/private_schema.xsd +++ b/lib/grm/src/grm/dom_render/graphics_tree/private_schema.xsd @@ -6,12 +6,18 @@ + + + + + + @@ -19,9 +25,14 @@ + + + + + @@ -54,6 +65,7 @@ + @@ -63,12 +75,14 @@ + + @@ -89,6 +103,7 @@ + @@ -158,6 +173,7 @@ + @@ -172,6 +188,7 @@ + @@ -196,6 +213,7 @@ + @@ -244,21 +262,40 @@ - - + + + + + + + - - + + + + + + + + + + + + + + + + + + - - @@ -328,32 +365,32 @@ - - + + - - + + - - + + - - + + @@ -486,11 +523,13 @@ - + + + @@ -512,17 +551,19 @@ - - + + + + - - + + @@ -530,12 +571,25 @@ - - + + + + + + + + + + + + + + + @@ -700,6 +754,7 @@ + diff --git a/lib/grm/src/grm/dom_render/graphics_tree/schema.xsd b/lib/grm/src/grm/dom_render/graphics_tree/schema.xsd index 42117d84c..cfac347be 100644 --- a/lib/grm/src/grm/dom_render/graphics_tree/schema.xsd +++ b/lib/grm/src/grm/dom_render/graphics_tree/schema.xsd @@ -9,13 +9,7 @@ - - - - - - @@ -29,7 +23,6 @@ - @@ -46,10 +39,6 @@ - - - - @@ -144,7 +133,7 @@ - + @@ -153,11 +142,11 @@ - + @@ -212,13 +201,14 @@ - - + + - + + @@ -232,6 +222,7 @@ + @@ -239,7 +230,7 @@ - + @@ -267,6 +258,7 @@ + @@ -323,8 +315,9 @@ - + + @@ -338,11 +331,9 @@ - - @@ -406,11 +397,12 @@ + - + @@ -549,36 +541,71 @@ - - + + - - - - - + + + - - - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + @@ -587,6 +614,7 @@ + @@ -595,6 +623,8 @@ + + @@ -679,7 +709,7 @@ - + @@ -690,10 +720,10 @@ - - + + - + @@ -705,10 +735,10 @@ - - + + - + @@ -717,10 +747,10 @@ - - + + - + @@ -733,10 +763,10 @@ - - + + - + @@ -770,10 +800,11 @@ + - + @@ -785,7 +816,7 @@ - + @@ -794,6 +825,7 @@ + @@ -830,6 +862,7 @@ + @@ -858,7 +891,7 @@ - + @@ -896,6 +929,7 @@ + @@ -905,7 +939,7 @@ - + @@ -961,8 +995,8 @@ - - + + @@ -971,8 +1005,8 @@ - - + + @@ -1014,29 +1048,12 @@ - - - - - - - - - - - - - - - - - - - + + @@ -1060,7 +1077,6 @@ - @@ -1075,7 +1091,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1477,11 +1537,13 @@ - - + + + + diff --git a/lib/grm/src/grm/dom_render/render.cxx b/lib/grm/src/grm/dom_render/render.cxx index 88e0a42a4..425479caa 100644 --- a/lib/grm/src/grm/dom_render/render.cxx +++ b/lib/grm/src/grm/dom_render/render.cxx @@ -11,6 +11,8 @@ #include +#include +#include #include #include #include @@ -26,6 +28,7 @@ #include #include #include +#include #include #include "gks.h" #include "gr.h" @@ -67,7 +70,8 @@ ManageCustomColorIndex custom_color_index_manager; //! This vector is used for storing element types which children get processed. Other types' children will be ignored static std::set parent_types = { - "axes_text_group", + "angle_line", + "arc_grid_line", "axis", "bar", "central_region", @@ -85,9 +89,9 @@ static std::set parent_types = { "legend", "pie_segment", "plot", - "polar_axes", "polar_bar", "marginal_heatmap_plot", + "rho_axes", "root", "series_barplot", "series_contour", @@ -98,13 +102,14 @@ static std::set parent_types = { "series_imshow", "series_isosurface", "series_line", - "series_nonuniformheatmap", - "series_nonuniformpolar_heatmap", + "series_nonuniform_heatmap", + "series_nonuniform_polar_heatmap", "series_pie", "series_plot3", - "series_polar", "series_polar_heatmap", "series_polar_histogram", + "series_polar_line", + "series_polar_scatter", "series_quiver", "series_scatter", "series_scatter3", @@ -119,18 +124,19 @@ static std::set parent_types = { "side_region", "side_plot_region", "text_region", + "theta_axes", "tick_group", }; static std::set drawable_types = { - "axes_3d", "cellarray", + "axes_3d", "cell_array", "draw_arc", "draw_graphics", "draw_image", "draw_rect", "fill_arc", "fill_area", "fill_rect", "grid", "grid_3d", "isosurface_render", "layout_grid", "layout_grid_element", - "legend", "nonuniformcellarray", + "legend", "nonuniform_cell_array", "panzoom", "polyline", "polyline_3d", "polymarker", "polymarker_3d", "text", @@ -141,70 +147,66 @@ static std::set drawable_kinds = { "contour", "contourf", "hexbin", "isosurface", "quiver", "shade", "surface", "tricontour", "trisurface", "volume", }; -static std::set valid_context_keys = {"absolute_downwards", - "absolute_upwards", - "bin_counts", - "bin_edges", - "bin_widths", - "bins", - "c", - "c_rgb", - "c_ind", - "classes", - "color_ind_values", - "color_rgb_values", - "data", - "directions", - "fill_color_rgb", - "indices", - "int_limits_high", - "int_limits_low", - "labels", - "line_color_rgb", - "line_color_indices", - "line_types", - "line_widths", - "marker_color_indices", - "marker_sizes", - "marker_types", - "phi", - "positions", - "px", - "py", - "pz", - "r", - "relative_downwards", - "relative_upwards", - "scales", - "specs", - "theta", - "u", - "ups", - "v", - "weights", - "x", - "xi", - "y", - "y_labels", - "z", - "z_dims"}; +static std::set valid_context_attributes = {"absolute_downwards", + "absolute_upwards", + "bin_counts", + "bin_edges", + "bin_widths", + "bins", + "c", + "c_rgb", + "c_ind", + "classes", + "color_ind_values", + "color_rgb_values", + "data", + "directions", + "fill_color_rgb", + "indices", + "int_limits_high", + "int_limits_low", + "labels", + "line_color_rgb", + "line_color_indices", + "line_types", + "line_widths", + "marker_color_indices", + "marker_sizes", + "marker_types", + "phi", + "positions", + "px", + "py", + "pz", + "r", + "relative_downwards", + "relative_upwards", + "scales", + "specs", + "theta", + "u", + "v", + "weights", + "x", + "xi", + "y", + "y_labels", + "z", + "z_dims", + "_x_org", + "_y_org", + "_z_org"}; + +static std::set valid_context_keys = valid_context_attributes; static std::set polar_kinds = { - "polar", - "polar_histogram", - "polar_heatmap", - "nonuniformpolar_heatmap", + "nonuniform_polar_heatmap", "polar_heatmap", "polar_histogram", "polar_line", "polar_scatter", }; static std::set kinds_3d = { "wireframe", "surface", "plot3", "scatter3", "trisurface", "volume", "isosurface", }; -static std::set kinds_with_possible_label = { - "barplot", "contour", "contourf", "heatmap", "hexbin", "hist", "line", - "marginal_heatmap", "quiver", "scatter", "shade", "stairs", "stem", "tricontour", -}; - static std::map symbol_to_meters_per_unit{ {"m", 1.0}, {"dm", 0.1}, {"cm", 0.01}, {"mm", 0.001}, {"in", 0.0254}, {"\"", 0.0254}, {"ft", 0.3048}, {"'", 0.0254}, {"pc", 0.0254 / 6.0}, {"pt", 0.0254 / 72.0}, @@ -228,22 +230,25 @@ static bool redraw_ws = false; static std::map> bounding_map; static std::map>> tick_modification_map; -static string_map_entry_t kind_to_fmt[] = {{"line", "xys"}, {"hexbin", "xys"}, - {"polar", "xys"}, {"shade", "xys"}, - {"stem", "xys"}, {"stairs", "xys"}, - {"contour", "xyzc"}, {"contourf", "xyzc"}, - {"tricontour", "xyzc"}, {"trisurface", "xyzc"}, - {"surface", "xyzc"}, {"wireframe", "xyzc"}, - {"plot3", "xyzc"}, {"scatter", "xyzc"}, - {"scatter3", "xyzc"}, {"quiver", "xyuv"}, - {"heatmap", "xyzc"}, {"hist", "x"}, - {"barplot", "y"}, {"isosurface", "z"}, - {"imshow", "z"}, {"nonuniformheatmap", "xyzc"}, - {"polar_histogram", "x"}, {"pie", "x"}, - {"volume", "z"}, {"marginal_heatmap", "xyzc"}, - {"polar_heatmap", "xyzc"}, {"nonuniformpolar_heatmap", "xyzc"}}; - -static string_map_t *fmt_map = string_map_new_with_data(array_size(kind_to_fmt), kind_to_fmt); +static string_map_entry_t kind_to_fmt[] = { + {"line", "xys"}, {"hexbin", "xys"}, + {"polar_line", "xys"}, {"shade", "xys"}, + {"stem", "xys"}, {"stairs", "xys"}, + {"contour", "xyzc"}, {"contourf", "xyzc"}, + {"tricontour", "xyzc"}, {"trisurface", "xyzc"}, + {"surface", "xyzc"}, {"wireframe", "xyzc"}, + {"plot3", "xyzc"}, {"scatter", "xyzc"}, + {"scatter3", "xyzc"}, {"quiver", "xyuv"}, + {"heatmap", "xyzc"}, {"hist", "x"}, + {"barplot", "y"}, {"isosurface", "z"}, + {"imshow", "z"}, {"nonuniform_heatmap", "xyzc"}, + {"polar_histogram", "x"}, {"pie", "x"}, + {"volume", "z"}, {"marginal_heatmap", "xyzc"}, + {"polar_heatmap", "xyzc"}, {"nonuniform_polar_heatmap", "xyzc"}, + {"polar_scatter", "xys"}, +}; + +static string_map_t *fmt_map = string_map_new_with_data(std::size(kind_to_fmt), kind_to_fmt); enum class del_values { @@ -369,6 +374,10 @@ static std::map scientific_format_string_to_int{ {"textex", 2}, {"mathtex", 3}, }; +static std::map error_bar_style_string_to_int{ + {"line", 0}, + {"area", 1}, +}; static std::map text_align_horizontal_string_to_int{ {"normal", 0}, {"left", 1}, @@ -388,11 +397,24 @@ static std::map model_string_to_int{ {"rgb", 0}, {"hsv", 1}, }; +static std::map clip_region_string_to_int{ + {"quadratic", 0}, + {"elliptic", 1}, +}; +static std::map resample_method_string_to_int{ + {"default", GKS_K_RESAMPLE_DEFAULT}, + {"nearest", GKS_K_RESAMPLE_NEAREST}, + {"linear", GKS_K_RESAMPLE_LINEAR}, + {"lanczos", GKS_K_RESAMPLE_LANCZOS}, +}; /* ~~~~~~~~~~~~~~~~~~~~~~~~~ static function header ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +static void processRhoAxes(const std::shared_ptr &element, const std::shared_ptr &context); static void processTickGroup(const std::shared_ptr &element, const std::shared_ptr &context); +static void processThetaAxes(const std::shared_ptr &element, + const std::shared_ptr &context); /* ~~~~~~~~~~~~~~~~~~~~~~~~~ utility functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ @@ -410,9 +432,9 @@ static bool isUniformData(const std::shared_ptr &element, const st { std::string x_key, y_key, kind; kind = static_cast(element->getAttribute("kind")); - if (str_equals_any(kind, "line", "scatter", "pie", "polar", "polar_histogram", "polar_heatmap", "imshow", "hist", - "barplot", "stem", "stairs") || - std::find(kinds_3d.begin(), kinds_3d.end(), kind) != kinds_3d.end()) + if (str_equals_any(kind, "line", "scatter", "pie", "polar_line", "polar_histogram", "polar_heatmap", "polar_scatter", + "imshow", "hist", "barplot", "stem", "stairs") || + kinds_3d.find(kind) != kinds_3d.end()) return false; if (kind == "heatmap" && (!element->hasAttribute("x") || !element->hasAttribute("y"))) @@ -519,7 +541,7 @@ static double getMinViewport(const std::shared_ptr &element, bool return min_vp; } -static std::tuple getColorbarAttributes(std::string kind, std::shared_ptr plot) +static std::tuple getColorbarAttributes(const std::string &kind, const std::shared_ptr &plot) { double offset = 0.0; int colors = 256; @@ -540,7 +562,7 @@ static std::tuple getColorbarAttributes(std::string kind, std::shar else colors = PLOT_DEFAULT_CONTOUR_LEVELS; } - if (kind == "polar_heatmap") + if (kind == "polar_heatmap" || kind == "nonuniform_polar_heatmap") { offset = PLOT_POLAR_COLORBAR_OFFSET; } @@ -555,11 +577,42 @@ static double getLightness(int color) { unsigned char rgb[sizeof(int)]; - gr_inqcolor(color, (int *)rgb); + gr_inqcolor(color, reinterpret_cast(rgb)); double y = (0.2126729 * rgb[0] / 255 + 0.7151522 * rgb[1] / 255 + 0.0721750 * rgb[2] / 255); return 116 * pow(y / 100, 1.0 / 3) - 16; } +// transform single coordinate (like x or y) into range (and or log scale) +// first transform into range and then log scale +static double transformCoordinate(double value, double v_min, double v_max, double range_min, double range_max, + bool log_scale = false) +{ + if (log_scale) + { + if (range_min != 0.0 || range_max != 0.0) + { + value = (range_max - range_min) * (value - v_min) / (v_max - v_min) + range_min; + } + else + { + range_min = v_min; + range_max = v_max; + } + return (log10(value) - range_min) * range_max / (range_max - range_min); + } + return (range_max - range_min) * (value - v_min) / (v_max - v_min) + range_min; +} + +static void transformCoordinatesVector(std::vector &coords, double v_min, double v_max, double range_min, + double range_max, bool log_scale = false) +{ + // TODO: does this method actually work correctly? + for (auto &coord : coords) + { + coord = transformCoordinate(coord, v_min, v_max, range_min, range_max, log_scale); + } +} + static void resetOldBoundingBoxes(const std::shared_ptr &element) { if (getenv("GRDISPLAY") && strcmp(getenv("GRDISPLAY"), "edit") == 0) @@ -677,7 +730,6 @@ static void clearOldChildren(del_values *del, const std::shared_ptr &element, double *w, double *h) { double tbx[4], tby[4]; - unsigned int num_labels; std::vector labels; *w = 0; @@ -701,7 +753,6 @@ static void legendSize(const std::shared_ptr &element, double *w, static void legendSize(const std::vector &labels, double *w, double *h) { double tbx[4], tby[4]; - unsigned int num_labels; *w = 0; *h = 0; @@ -717,7 +768,7 @@ static void legendSize(const std::vector &labels, double *w, double } } -static void sidePlotMargin(const std::shared_ptr side_region, double *margin, double inc, +static void sidePlotMargin(const std::shared_ptr &side_region, double *margin, double inc, bool aspect_ratio_scale, double aspect_ratio_ws, double start_aspect_ratio_ws) { if (side_region->querySelectors("side_plot_region") || @@ -739,8 +790,8 @@ static void sidePlotMargin(const std::shared_ptr side_region, doub } } -static void capSidePlotMarginInNonKeepAspectRatio(const std::shared_ptr side_region, double *margin, - std::string kind) +static void capSidePlotMarginInNonKeepAspectRatio(const std::shared_ptr &side_region, double *margin, + const std::string &kind) { // TODO: Overwork max value workaround if (side_region->querySelectors("side_plot_region")) @@ -756,7 +807,7 @@ static void capSidePlotMarginInNonKeepAspectRatio(const std::shared_ptr element, double *vp_x_min, +static void calculateCentralRegionMarginOrDiagFactor(const std::shared_ptr &element, double *vp_x_min, double *vp_x_max, double *vp_y_min, double *vp_y_max, bool diag_factor = false) { @@ -775,7 +826,7 @@ static void calculateCentralRegionMarginOrDiagFactor(const std::shared_ptr(plot_parent->getAttribute("kind")); + kind = static_cast(plot_parent->getAttribute("_kind")); keep_aspect_ratio = static_cast(plot_parent->getAttribute("keep_aspect_ratio")); only_quadratic_aspect_ratio = static_cast(plot_parent->getAttribute("only_quadratic_aspect_ratio")); @@ -867,6 +918,8 @@ static void calculateCentralRegionMarginOrDiagFactor(const std::shared_ptr 0) { double x_center, y_center, r; @@ -995,6 +1048,7 @@ static void calculateCentralRegionMarginOrDiagFactor(const std::shared_ptr else if (location == "left") { min_vp = getMinViewport(element, true); - global_render->setViewport(element, grm_max(viewport[0] - (offset_rel + width_rel), min_vp), viewport[0], - viewport[2], viewport[3]); + global_render->setViewport(element, grm_max(viewport[0] - (offset_rel + width_rel), min_vp), + viewport[0] - offset_rel, viewport[2], viewport[3]); element->setAttribute("_viewport_x_min_org", grm_max(viewport[0] - (offset_rel + width_rel), min_vp)); - element->setAttribute("_viewport_x_max_org", viewport[0]); + element->setAttribute("_viewport_x_max_org", viewport[0] - offset_rel); element->setAttribute("_viewport_y_min_org", viewport[2]); element->setAttribute("_viewport_y_max_org", viewport[3]); } @@ -1097,11 +1151,11 @@ static void setViewportForSideRegionElements(const std::shared_ptr { min_vp = getMinViewport(element, false); global_render->setViewport(element, viewport[0], viewport[1], - grm_max(viewport[2] - (offset_rel + width_rel), min_vp), viewport[2]); + grm_max(viewport[2] - (offset_rel + width_rel), min_vp), viewport[2] - offset_rel); element->setAttribute("_viewport_x_min_org", viewport[0]); element->setAttribute("_viewport_x_max_org", viewport[1]); element->setAttribute("_viewport_y_min_org", grm_max(viewport[2] - (offset_rel + width_rel), min_vp)); - element->setAttribute("_viewport_y_max_org", viewport[2]); + element->setAttribute("_viewport_y_max_org", viewport[2] - offset_rel); } } @@ -1132,9 +1186,8 @@ static void calculateViewport(const std::shared_ptr &element) double vp[4]; double metric_width, metric_height; double aspect_ratio_ws; - std::string kind; - /* when grids are being used for layouting the subplot information is stored in the parent of the plot */ + /* when grids are being used for layouting the plot information is stored in the parent of the plot */ if (element->parentElement()->localName() == "layout_grid_element") { vp[0] = static_cast(element->parentElement()->getAttribute("plot_x_min")); @@ -1149,7 +1202,6 @@ static void calculateViewport(const std::shared_ptr &element) vp[2] = static_cast(element->getAttribute("plot_y_min")); vp[3] = static_cast(element->getAttribute("plot_y_max")); } - kind = static_cast(element->getAttribute("kind")); GRM::Render::getFigureSize(nullptr, nullptr, &metric_width, &metric_height); aspect_ratio_ws = metric_width / metric_height; @@ -1176,9 +1228,6 @@ static void calculateViewport(const std::shared_ptr &element) double plot_viewport[4]; double offset = PLOT_DEFAULT_SIDEREGION_OFFSET, width = PLOT_DEFAULT_SIDEREGION_WIDTH; std::string location = PLOT_DEFAULT_SIDEREGION_LOCATION, kind; - double max_vp, min_vp; - double offset_rel, width_rel; - double metric_width, metric_height; bool keep_aspect_ratio = false, uniform_data = true, only_quadratic_aspect_ratio = false; auto plot_parent = element; @@ -1197,7 +1246,9 @@ static void calculateViewport(const std::shared_ptr &element) static_cast(plot_parent->getAttribute("plot_y_max")) / (DEFAULT_ASPECT_RATIO_FOR_SCALING); keep_aspect_ratio = static_cast(plot_parent->getAttribute("keep_aspect_ratio")); only_quadratic_aspect_ratio = static_cast(plot_parent->getAttribute("only_quadratic_aspect_ratio")); - kind = static_cast(plot_parent->getAttribute("kind")); + kind = static_cast(plot_parent->getAttribute("_kind")); + + if (element->querySelectors("colorbar")) width = PLOT_DEFAULT_COLORBAR_WIDTH; if (keep_aspect_ratio && only_quadratic_aspect_ratio) { @@ -1277,23 +1328,28 @@ static void calculateViewport(const std::shared_ptr &element) plot_viewport[3] = static_cast(plot_parent->getAttribute("plot_y_max")) / (DEFAULT_ASPECT_RATIO_FOR_SCALING); location = static_cast(element->parentElement()->getAttribute("location")); - kind = static_cast(plot_parent->getAttribute("kind")); + kind = static_cast(plot_parent->getAttribute("_kind")); // apply text width to the side_region if (kind != "imshow") { if (location == "top") { - if (!element->parentElement()->hasAttribute("marginal_heatmap_side_plot")) + bool has_title = (element->parentElement()->hasAttribute("text_is_title") && + static_cast(element->parentElement()->getAttribute("text_is_title"))); + if (!element->parentElement()->hasAttribute("marginal_heatmap_side_plot") || + !static_cast(element->parentElement()->getAttribute("marginal_heatmap_side_plot"))) + { + width += (0.025 + (has_title ? 0.075 : 0.05)) * (plot_viewport[3] - plot_viewport[2]); + } + if (!has_title && element->parentElement()->querySelectors("colorbar")) { - width += (0.025 + ((element->parentElement()->hasAttribute("text_is_title") && - static_cast(element->parentElement()->getAttribute("text_is_title"))) - ? 0.075 - : 0.05)) * - (plot_viewport[3] - plot_viewport[2]); + width = 0.0; + if (polar_kinds.count(kind) > 0) width += 0.025; } if (element->parentElement()->hasAttribute("offset")) offset = static_cast(element->parentElement()->getAttribute("offset")); + if (kinds_3d.count(kind) > 0 && !has_title) offset = PLOT_DEFAULT_COLORBAR_OFFSET; if (element->parentElement()->hasAttribute("width")) offset += static_cast(element->parentElement()->getAttribute("width")); } @@ -1307,7 +1363,7 @@ static void calculateViewport(const std::shared_ptr &element) } if (location == "right") { - width += (0.075 + 0.05) * (plot_viewport[1] - plot_viewport[0]); + width += 0.05 * (plot_viewport[1] - plot_viewport[0]); } } @@ -1328,10 +1384,10 @@ static void calculateViewport(const std::shared_ptr &element) static_cast(plot_parent->getAttribute("plot_y_min")) / (DEFAULT_ASPECT_RATIO_FOR_SCALING); plot_viewport[3] = static_cast(plot_parent->getAttribute("plot_y_max")) / (DEFAULT_ASPECT_RATIO_FOR_SCALING); - location = static_cast(element->parentElement()->getAttribute("location")); keep_aspect_ratio = static_cast(plot_parent->getAttribute("keep_aspect_ratio")); only_quadratic_aspect_ratio = static_cast(plot_parent->getAttribute("only_quadratic_aspect_ratio")); - kind = static_cast(plot_parent->getAttribute("kind")); + location = static_cast(element->parentElement()->getAttribute("location")); + kind = static_cast(plot_parent->getAttribute("_kind")); if (keep_aspect_ratio && only_quadratic_aspect_ratio) { @@ -1357,6 +1413,44 @@ static void calculateViewport(const std::shared_ptr &element) if (element->parentElement()->hasAttribute("width")) width = static_cast(element->parentElement()->getAttribute("width")); + if (element->parentElement()->hasAttribute("text_content")) + { + if (location == "right") + { + offset += 0.05 * (plot_viewport[1] - plot_viewport[0]); + } + else if (location == "left") + { + offset += (0.075 + 0.05) * (plot_viewport[1] - plot_viewport[0]); + } + else if (location == "bottom") + { + offset += (0.075 + 0.05) * (plot_viewport[3] - plot_viewport[2]); + } + else if (location == "top") + { + if (!(element->parentElement()->hasAttribute("text_is_title") && + static_cast(element->parentElement()->getAttribute("text_is_title")))) + { + offset += 0.05 * (plot_viewport[3] - plot_viewport[2]); + if (polar_kinds.count(kind) > 0) offset += 0.05; + if (kinds_3d.count(kind) > 0) offset -= 0.05; + } + else + { + if (kinds_3d.count(kind) > 0) offset = 0.02; + } + } + } + else + { + // 180 is bigger than 0 so a adjustment is needed + if (polar_kinds.count(kind) > 0 && location == "left") offset += 0.01; + // with no label there must be an extra offset so that the tick-labels don't get overlapped + if (polar_kinds.count(kind) == 0 && kinds_3d.count(kind) == 0 && location == "left") offset += 0.05; + if (polar_kinds.count(kind) == 0 && kinds_3d.count(kind) == 0 && location == "bottom") offset += 0.05; + } + setViewportForSideRegionElements(element, offset, width, false); } else if (element->localName() == "colorbar") // TODO: adjust this calculation when texts are included in side_region @@ -1410,6 +1504,8 @@ static void calculateViewport(const std::shared_ptr &element) viewport[2] = static_cast(central_region->getAttribute("_viewport_y_min_org")); viewport[3] = static_cast(central_region->getAttribute("_viewport_y_max_org")); + kind = static_cast(element->parentElement()->getAttribute("_kind")); + if (polar_kinds.count(kind) > 0) location = 11; if (element->hasAttribute("location")) { if (element->getAttribute("location").isInt()) @@ -1427,7 +1523,6 @@ static void calculateViewport(const std::shared_ptr &element) } keep_aspect_ratio = static_cast(element->parentElement()->getAttribute("keep_aspect_ratio")); start_aspect_ratio_ws = static_cast(element->parentElement()->getAttribute("_start_aspect_ratio")); - kind = static_cast(element->parentElement()->getAttribute("kind")); if (!keep_aspect_ratio) { @@ -1518,7 +1613,7 @@ static void calculateViewport(const std::shared_ptr &element) else { double tbx[4], tby[4]; - int num_labels = labels.size(); + auto num_labels = static_cast(labels.size()); w = 0; h = 0; @@ -1772,17 +1867,11 @@ static std::string getLocalName(const std::shared_ptr &element) static bool isDrawable(const std::shared_ptr &element) { auto local_name = getLocalName(element); - if (drawable_types.find(local_name) != drawable_types.end()) - { - return true; - } + if (drawable_types.find(local_name) != drawable_types.end()) return true; if (local_name == "series") { auto kind = static_cast(element->getAttribute("kind")); - if (drawable_kinds.find(kind) != drawable_kinds.end()) - { - return true; - } + if (drawable_kinds.find(kind) != drawable_kinds.end()) return true; } return false; } @@ -1835,6 +1924,78 @@ std::string scientificFormatIntToString(int scientific_format) throw std::logic_error("Given scientific_format is unknown.\n"); } +int errorBarStyleStringToInt(const std::string &error_bar_style_str) +{ + if (error_bar_style_string_to_int.count(error_bar_style_str)) + return error_bar_style_string_to_int[error_bar_style_str]; + else + { + logger((stderr, "Got unknown error_bar_style \"%s\"\n", error_bar_style_str.c_str())); + throw std::logic_error("Given error_bar_style is unknown.\n"); + } +} + +std::string errorBarStyleIntToString(int error_bar_style) +{ + for (auto const &map_elem : error_bar_style_string_to_int) + { + if (map_elem.second == error_bar_style) + { + return map_elem.first; + } + } + logger((stderr, "Got unknown error_bar_style \"%i\"\n", error_bar_style)); + throw std::logic_error("Given error_bar_style is unknown.\n"); +} + +int clipRegionStringToInt(const std::string &clip_region_str) +{ + if (clip_region_string_to_int.count(clip_region_str)) + return clip_region_string_to_int[clip_region_str]; + else + { + logger((stderr, "Got unknown clip_region \"%s\"\n", clip_region_str.c_str())); + throw std::logic_error("Given clip_region is unknown.\n"); + } +} + +std::string clipRegionIntToString(int clip_region) +{ + for (auto const &map_elem : clip_region_string_to_int) + { + if (map_elem.second == clip_region) + { + return map_elem.first; + } + } + logger((stderr, "Got unknown clip_region \"%i\"\n", clip_region)); + throw std::logic_error("Given clip_region is unknown.\n"); +} + +int resampleMethodStringToInt(const std::string &resample_method_str) +{ + if (resample_method_string_to_int.count(resample_method_str)) + return resample_method_string_to_int[resample_method_str]; + else + { + logger((stderr, "Got unknown resample_method \"%s\"\n", resample_method_str.c_str())); + throw std::logic_error("Given resample_method is unknown.\n"); + } +} + +std::string resampleMethodIntToString(int resample_method) +{ + for (auto const &map_elem : resample_method_string_to_int) + { + if (map_elem.second == resample_method) + { + return map_elem.first; + } + } + logger((stderr, "Got unknown resample_method \"%i\"\n", resample_method)); + throw std::logic_error("Given resample_method is unknown.\n"); +} + int getVolumeAlgorithm(const std::shared_ptr &element) { int algorithm; @@ -1858,7 +2019,7 @@ int getVolumeAlgorithm(const std::shared_ptr &element) PushDrawableToZQueue::PushDrawableToZQueue( std::function &, const std::shared_ptr &)> draw_function) - : drawFunction(draw_function) + : drawFunction(std::move(draw_function)) { ; } @@ -1879,24 +2040,23 @@ void PushDrawableToZQueue::operator()(const std::shared_ptr &eleme gr_savecontext(context_id); parent_to_context[parent] = context_id; } - auto drawable = - std::shared_ptr(new Drawable(element, context, context_id, z_index_manager.getZIndex(), drawFunction)); + auto drawable = std::make_shared(element, context, context_id, z_index_manager.getZIndex(), drawFunction); drawable->insertionIndex = (int)z_queue.size(); custom_color_index_manager.savecontext(context_id); z_queue.push(drawable); } -static double autoTick(double amin, double amax) +static double autoTick(double min, double max) { double tick_size[] = {5.0, 2.0, 1.0, 0.5, 0.2, 0.1, 0.05, 0.02, 0.01}; double scale, tick; int i, n; - scale = pow(10.0, (int)(log10(amax - amin))); + scale = pow(10.0, (int)(log10(max - min))); tick = 1.0; for (i = 0; i < 9; i++) { - n = (int)((amax - amin) / scale / tick_size[i]); + n = (int)((max - min) / scale / tick_size[i]); if (n > 7) { tick = tick_size[i - 1]; @@ -1907,79 +2067,6 @@ static double autoTick(double amin, double amax) return tick; } -static double autoTickRingsPolar(double rmax, int &rings, const std::string &norm) -{ - double scale; - bool is_decimal = false; - std::vector *whichVector; - std::vector largeRings = {6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; - std::vector normalRings = {3, 4, 5, 6, 7}; - - // -1 --> auto rings - if (rings == -1) - { - if (norm == "cdf") - { - rings = 4; - return 1.0 / rings; - } - - if (rmax > 20) - { - whichVector = &largeRings; - } - else - { - whichVector = &normalRings; - } - scale = ceil(abs(log10(rmax))); - if (rmax < 1.0) - { - is_decimal = true; - rmax = static_cast(ceil(rmax * pow(10.0, scale))); - } - - while (true) - { - for (int i : *whichVector) - { - if (static_cast(rmax) % i == 0) - { - if (is_decimal) rmax = rmax / pow(10.0, scale); - rings = i; - return rmax / rings; - } - } - // rmax not divisible by whichVector - ++rmax; - } - } - - // given rings - if (norm == "cdf") return 1.0 / rings; - - if (rmax > rings) - { - return (static_cast(rmax) + (rings - (static_cast(rmax) % rings))) / rings; - } - else if (rmax > (rings * 0.6)) - { - // returns rings / rings -> 1.0 so that rmax = rings * tick -> rings. Number of rings is rmax then - return 1.0; - } - scale = ceil(abs(log10(rmax))); - rmax = static_cast(rmax * pow(10.0, scale)); - if (static_cast(rmax) % rings == 0) - { - rmax = rmax / pow(10.0, scale); - return rmax / rings; - } - rmax += rings - (static_cast(rmax) % rings); - rmax = rmax / pow(10.0, scale); - - return rmax / rings; -} - static void clearAxisAttributes(const std::shared_ptr &axis) { if (axis->hasAttribute("min_value")) axis->removeAttribute("min_value"); @@ -1989,6 +2076,7 @@ static void clearAxisAttributes(const std::shared_ptr &axis) if (axis->hasAttribute("tick")) axis->removeAttribute("tick"); if (axis->hasAttribute("major_count")) axis->removeAttribute("major_count"); if (axis->hasAttribute("tick_size")) axis->removeAttribute("tick_size"); + if (axis->hasAttribute("_tick_size_org")) axis->removeAttribute("_tick_size_org"); if (axis->hasAttribute("tick_orientation")) axis->removeAttribute("tick_orientation"); } @@ -2322,15 +2410,15 @@ static void lineHelper(const std::shared_ptr &element, const std:: } } -static std::shared_ptr getSubplotElement(const std::shared_ptr &element) +static std::shared_ptr getPlotElement(const std::shared_ptr &element) { auto ancestor = element; while (ancestor->localName() != "figure") { - bool ancestor_is_subplot_group = + bool ancestor_has_plot_group = (ancestor->hasAttribute("plot_group") && static_cast(ancestor->getAttribute("plot_group"))); - if (ancestor->localName() == "layout_grid_element" || ancestor_is_subplot_group) + if (ancestor->localName() == "layout_grid_element" || ancestor_has_plot_group) { return ancestor; } @@ -2346,19 +2434,31 @@ static void getTickSize(const std::shared_ptr &element, double &ti { if (element->hasAttribute("tick_size") && element->parentElement()->localName() == "colorbar") { - double plot_viewport[2], tick_size_rel; + double tick_size_rel; double metric_width, metric_height; bool keep_aspect_ratio = false, uniform_data = true, only_quadratic_aspect_ratio = false; auto plot_parent = element->parentElement(); getPlotParent(plot_parent); - plot_viewport[0] = static_cast(plot_parent->getAttribute("_viewport_x_min_org")); - plot_viewport[1] = static_cast(plot_parent->getAttribute("_viewport_x_max_org")); - GRM::Render::getFigureSize(nullptr, nullptr, &metric_width, &metric_height); auto aspect_ratio_ws = metric_width / metric_height; - tick_size = static_cast(element->getAttribute("tick_size")); + if (element->hasAttribute("_tick_size_set_by_user")) + { + tick_size = static_cast(element->getAttribute("_tick_size_set_by_user")); + } + else + { + if (element->hasAttribute("_tick_size_org")) + { + tick_size = static_cast(element->getAttribute("_tick_size_org")); + } + else + { + tick_size = static_cast(element->getAttribute("tick_size")); + element->setAttribute("_tick_size_org", tick_size); + } + } keep_aspect_ratio = static_cast(plot_parent->getAttribute("keep_aspect_ratio")); only_quadratic_aspect_ratio = static_cast(plot_parent->getAttribute("only_quadratic_aspect_ratio")); @@ -2366,7 +2466,7 @@ static void getTickSize(const std::shared_ptr &element, double &ti if (keep_aspect_ratio && only_quadratic_aspect_ratio) { auto render = grm_get_render(); - auto kind = static_cast(plot_parent->getAttribute("kind")); + auto kind = static_cast(plot_parent->getAttribute("_kind")); for (const auto &series : plot_parent->querySelectors("central_region")->children()) { if (!starts_with(series->localName(), "series_")) continue; @@ -2394,7 +2494,7 @@ static void getTickSize(const std::shared_ptr &element, double &ti double viewport[4]; double default_diag_factor; std::shared_ptr central_region, central_region_parent; - auto kind = static_cast(plot_parent->getAttribute("kind")); + auto kind = static_cast(plot_parent->getAttribute("_kind")); central_region_parent = plot_parent; if (kind == "marginal_heatmap") central_region_parent = plot_parent->children()[0]; @@ -2433,9 +2533,9 @@ static void getTickSize(const std::shared_ptr &element, double &ti else { double viewport[4]; - auto plot_element = getSubplotElement(element); + auto plot_element = getPlotElement(element); std::shared_ptr central_region, central_region_parent; - auto kind = static_cast(plot_element->getAttribute("kind")); + auto kind = static_cast(plot_element->getAttribute("_kind")); central_region_parent = plot_element; if (kind == "marginal_heatmap") central_region_parent = plot_element->children()[0]; @@ -2468,8 +2568,8 @@ static void getMajorCount(const std::shared_ptr &element, const st } else { - if (str_equals_any(kind, "wireframe", "surface", "plot3", "scatter3", "polar", "trisurface", "polar_heatmap", - "nonuniformpolar_heatmap", "volume")) + if (str_equals_any(kind, "wireframe", "surface", "plot3", "scatter3", "polar_line", "trisurface", "polar_heatmap", + "nonuniform_polar_heatmap", "polar_scatter", "volume")) { major_count = 2; } @@ -2489,11 +2589,11 @@ static void getAxesInformation(const std::shared_ptr &element, con int major_count; std::shared_ptr central_region, central_region_parent; - auto subplot_element = getSubplotElement(element); - auto kind = static_cast(subplot_element->getAttribute("kind")); + auto plot_element = getPlotElement(element); + auto kind = static_cast(plot_element->getAttribute("_kind")); - central_region_parent = subplot_element; - if (kind == "marginal_heatmap") central_region_parent = subplot_element->children()[0]; + central_region_parent = plot_element; + if (kind == "marginal_heatmap") central_region_parent = plot_element->children()[0]; for (const auto &child : central_region_parent->children()) { if (child->localName() == "central_region") @@ -2503,7 +2603,7 @@ static void getAxesInformation(const std::shared_ptr &element, con } } - auto scale = static_cast(subplot_element->getAttribute("scale")); + auto scale = static_cast(plot_element->getAttribute("scale")); auto xmin = static_cast(central_region->getAttribute("window_x_min")); auto xmax = static_cast(central_region->getAttribute("window_x_max")); auto ymin = static_cast(central_region->getAttribute("window_y_min")); @@ -2517,7 +2617,7 @@ static void getAxesInformation(const std::shared_ptr &element, con } else { - if (element->hasAttribute("x_major")) + if (element->hasAttribute("x_major") && kind != "barplot") { x_major = static_cast(element->getAttribute("x_major")); } @@ -2530,16 +2630,12 @@ static void getAxesInformation(const std::shared_ptr &element, con auto barplots = central_region->querySelectorsAll("series_barplot"); for (const auto &barplot : barplots) { - if (!barplot->hasAttribute("style") || - static_cast(barplot->getAttribute("style")) == "default") + auto y_key = static_cast(barplot->getAttribute("y")); + std::vector y_vec = GRM::get>((*context)[y_key]); + if (size(y_vec) > 20 || xmax - xmin > 20) // 20 based on the looking of the resulting plots { - auto y_key = static_cast(barplot->getAttribute("y")); - std::vector y_vec = GRM::get>((*context)[y_key]); - if (size(y_vec) > 20) - { - problematic_bar_num = true; - break; - } + problematic_bar_num = true; + break; } } x_major = problematic_bar_num ? major_count : 1; @@ -2559,7 +2655,7 @@ static void getAxesInformation(const std::shared_ptr &element, con } else { - if (element->hasAttribute("x_tick")) + if (element->hasAttribute("x_tick") && kind != "barplot") { x_tick = static_cast(element->getAttribute("x_tick")); } @@ -2568,6 +2664,8 @@ static void getAxesInformation(const std::shared_ptr &element, con if (kind == "barplot") { x_tick = 1; + // 60 based on the looking of the resulting plots + if (x_major != 1 && xmax - xmin > 60) x_tick = autoTick(xmin, xmax) / x_major; } else { @@ -2714,8 +2812,8 @@ static void getAxes3dInformation(const std::shared_ptr &element, c std::shared_ptr central_region; auto draw_axes_group = element->parentElement(); - auto subplot_element = getSubplotElement(element); - for (const auto &child : subplot_element->children()) // don't need special case for marginal_heatmap cause it's 3d + auto plot_element = getPlotElement(element); + for (const auto &child : plot_element->children()) // don't need special case for marginal_heatmap cause it's 3d { if (child->localName() == "central_region") { @@ -2724,8 +2822,8 @@ static void getAxes3dInformation(const std::shared_ptr &element, c } } - auto kind = static_cast(subplot_element->getAttribute("kind")); - auto scale = static_cast(subplot_element->getAttribute("scale")); + auto kind = static_cast(plot_element->getAttribute("_kind")); + auto scale = static_cast(plot_element->getAttribute("scale")); auto zmin = static_cast(central_region->getAttribute("window_z_min")); auto zmax = static_cast(central_region->getAttribute("window_z_max")); @@ -2812,7 +2910,7 @@ void GRM::Render::getFigureSize(int *pixel_width, int *pixel_height, double *met double display_metric_width, display_metric_height; int display_pixel_width, display_pixel_height; double dpm[2], dpi[2]; - int tmp_size_i[2], pixel_size[2]; + int pixel_size[2]; double tmp_size_d[2], metric_size[2]; int i; std::string size_unit, size_type; @@ -2877,91 +2975,10 @@ void GRM::Render::getFigureSize(int *pixel_width, int *pixel_height, double *met metric_size[1] = PLOT_DEFAULT_HEIGHT / dpm[1]; } - if (pixel_width != nullptr) - { - *pixel_width = pixel_size[0]; - } - if (pixel_height != nullptr) - { - *pixel_height = pixel_size[1]; - } - if (metric_width != nullptr) - { - *metric_width = metric_size[0]; - } - if (metric_height != nullptr) - { - *metric_height = metric_size[1]; - } -} - -static void setNextColor(gr_color_type_t color_type, std::vector &color_indices, - std::vector &color_rgb_values, const std::shared_ptr &element) -{ - // TODO: is this method really needed? Cant it be replaced by set_next_color? - const static std::vector fallback_color_indices{989, 982, 980, 981, 996, 983, 995, 988, 986, 990, - 991, 984, 992, 993, 994, 987, 985, 997, 998, 999}; - static double saved_color[3]; - static int last_array_index = -1; - static unsigned int color_array_length = -1; - int current_array_index = last_array_index + 1; - int color_index = 0; - int reset = (color_type == GR_COLOR_RESET); - int gks_err_ind = GKS_K_NO_ERROR; - - if (reset) - { - last_array_index = -1; - color_array_length = -1; - return; - } - - if (color_indices.empty() && color_rgb_values.empty()) - { - color_indices = fallback_color_indices; - } - - if (last_array_index < 0 && !color_rgb_values.empty()) - { - gks_inq_color_rep(1, PLOT_CUSTOM_COLOR_INDEX, GKS_K_VALUE_SET, &gks_err_ind, &saved_color[0], &saved_color[1], - &saved_color[2]); - } - - current_array_index %= color_array_length; - - if (!color_indices.empty()) - { - color_index = color_indices[current_array_index]; - last_array_index = current_array_index; - } - else if (!color_rgb_values.empty()) - { - color_index = PLOT_CUSTOM_COLOR_INDEX; - global_render->setColorRep(element, PLOT_CUSTOM_COLOR_INDEX, color_rgb_values[current_array_index], - color_rgb_values[current_array_index + 1], color_rgb_values[current_array_index + 2]); - last_array_index = current_array_index + 2; - } - - if (color_type & GR_COLOR_LINE) - { - global_render->setLineColorInd(element, color_index); - } - if (color_type & GR_COLOR_MARKER) - { - global_render->setMarkerColorInd(element, color_index); - } - if (color_type & GR_COLOR_FILL) - { - global_render->setFillColorInd(element, color_index); - } - if (color_type & GR_COLOR_TEXT) - { - global_render->setTextColorInd(element, color_index); - } - if (color_type & GR_COLOR_BORDER) - { - global_render->setBorderColorInd(element, color_index); - } + if (pixel_width != nullptr) *pixel_width = pixel_size[0]; + if (pixel_height != nullptr) *pixel_height = pixel_size[1]; + if (metric_width != nullptr) *metric_width = metric_size[0]; + if (metric_height != nullptr) *metric_height = metric_size[1]; } void receiverFunction(int id, double x_min, double x_max, double y_min, double y_max) @@ -3025,9 +3042,9 @@ static void extendErrorBars(const std::shared_ptr &element, const auto str = std::to_string(id); global_root->setAttribute("_id", ++id); - (*context)["x" + str] = x; + (*context)["x" + str] = std::move(x); element->setAttribute("x", "x" + str); - (*context)["y" + str] = y; + (*context)["y" + str] = std::move(y); element->setAttribute("y", "y" + str); } @@ -3119,6 +3136,19 @@ std::vector getModel() return model; } +std::vector getContextAttributes() +{ + std::vector attributes; + attributes.reserve(valid_context_attributes.size()); + for (auto const &attr : valid_context_attributes) attributes.push_back(attr); + return attributes; +} + +void addValidContextKey(std::string key) +{ + valid_context_keys.emplace(key); +} + /* ~~~~~~~~~~~~~~~~~~~~~~~~~ attribute processing functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ static void processAlpha(const std::shared_ptr &element) @@ -3133,7 +3163,7 @@ static void processBorderColorInd(const std::shared_ptr &element) static void processMarginalHeatmapSidePlot(const std::shared_ptr &element) { - double viewport[4], window[4]; + double window[4]; double x_min, x_max, y_min, y_max, c_max; auto kind = static_cast(element->getAttribute("kind")); @@ -3141,24 +3171,20 @@ static void processMarginalHeatmapSidePlot(const std::shared_ptr & element->parentElement()->hasAttribute("marginal_heatmap_kind")) { auto location = static_cast(element->getAttribute("location")); - auto plot_group = element->parentElement(); - getPlotParent(plot_group); + auto plot_parent = element->parentElement(); + getPlotParent(plot_parent); applyMoveTransformation(element); - viewport[0] = static_cast(element->getAttribute("viewport_x_min")); - viewport[1] = static_cast(element->getAttribute("viewport_x_max")); - viewport[2] = static_cast(element->getAttribute("viewport_y_min")); - viewport[3] = static_cast(element->getAttribute("viewport_y_max")); - x_min = static_cast(plot_group->getAttribute("_x_lim_min")); - x_max = static_cast(plot_group->getAttribute("_x_lim_max")); - y_min = static_cast(plot_group->getAttribute("_y_lim_min")); - y_max = static_cast(plot_group->getAttribute("_y_lim_max")); - if (!std::isnan(static_cast(plot_group->getAttribute("_c_lim_max")))) + x_min = static_cast(plot_parent->getAttribute("_x_lim_min")); + x_max = static_cast(plot_parent->getAttribute("_x_lim_max")); + y_min = static_cast(plot_parent->getAttribute("_y_lim_min")); + y_max = static_cast(plot_parent->getAttribute("_y_lim_max")); + if (!std::isnan(static_cast(plot_parent->getAttribute("_c_lim_max")))) { - c_max = static_cast(plot_group->getAttribute("_c_lim_max")); + c_max = static_cast(plot_parent->getAttribute("_c_lim_max")); } else { - c_max = static_cast(plot_group->getAttribute("_z_lim_max")); + c_max = static_cast(plot_parent->getAttribute("_z_lim_max")); } if (element->hasAttribute("window_x_min")) window[0] = static_cast(element->getAttribute("window_x_min")); @@ -3207,6 +3233,11 @@ static void processCharUp(const std::shared_ptr &element) static_cast(element->getAttribute("char_up_y"))); } +static void processClipRegion(const std::shared_ptr &element) +{ + gr_setclipregion(static_cast(element->getAttribute("clip_region"))); +} + static void processClipTransformation(const std::shared_ptr &element) { gr_selectclipxform(static_cast(element->getAttribute("clip_transformation"))); @@ -3221,16 +3252,15 @@ std::string colormapIntToString(int colormap) { for (auto const &map_elem : colormap_string_to_int) { - if (map_elem.second == colormap) - { - return map_elem.first; - } + if (map_elem.second == colormap) return map_elem.first; } + logger((stderr, "Got unknown colormap \"%i\"\n", colormap)); + throw std::logic_error("The given colormap is unknown.\n"); } static void processColormap(const std::shared_ptr &element) { - int colormap; + int colormap = PLOT_DEFAULT_COLORMAP; if (element->getAttribute("colormap").isInt()) { colormap = static_cast(element->getAttribute("colormap")); @@ -3243,7 +3273,7 @@ static void processColormap(const std::shared_ptr &element) gr_setcolormap(colormap); } -static void processColorRep(const std::shared_ptr &element, const std::string attribute) +static void processColorRep(const std::shared_ptr &element, const std::string &attribute) { int index, hex_int; double red, green, blue; @@ -3323,7 +3353,7 @@ std::string fillIntStyleIntToString(int fill_int_style) static void processFillIntStyle(const std::shared_ptr &element) { - int fill_int_style; + int fill_int_style = 1; if (element->getAttribute("fill_int_style").isInt()) { fill_int_style = static_cast(element->getAttribute("fill_int_style")); @@ -3375,7 +3405,7 @@ std::string fillStyleIntToString(int fill_style) static void processFillStyle(const std::shared_ptr &element) { - int fill_style; + int fill_style = 1; if (element->getAttribute("fill_style").isInt()) { fill_style = static_cast(element->getAttribute("fill_int_style")); @@ -3422,11 +3452,10 @@ std::string fontIntToString(int font) { for (auto const &map_elem : font_string_to_int) { - if (map_elem.second == font) - { - return map_elem.first; - } + if (map_elem.second == font) return map_elem.first; } + logger((stderr, "Got unknown font \"%i\"\n", font)); + throw std::logic_error("The given font is unknown.\n"); } int fontPrecisionStringToInt(const std::string &font_precision_str) @@ -3438,11 +3467,10 @@ std::string fontPrecisionIntToString(int font_precision) { for (auto const &map_elem : font_precision_string_to_int) { - if (map_elem.second == font_precision) - { - return map_elem.first; - } + if (map_elem.second == font_precision) return map_elem.first; } + logger((stderr, "Got unknown font precision \"%i\"\n", font_precision)); + throw std::logic_error("The given font precision is unknown.\n"); } static void processFont(const std::shared_ptr &element) @@ -3494,7 +3522,7 @@ static void processIntegral(const std::shared_ptr &element, const int child_id = 0, id, i; std::shared_ptr fill_area, left_border, right_border; std::string str; - auto subplot_element = getSubplotElement(element); + auto plot_element = getPlotElement(element); auto series_element = element->parentElement()->parentElement(); double x_shift = 0; double x1, x2; @@ -3546,12 +3574,12 @@ static void processIntegral(const std::shared_ptr &element, const auto x = static_cast(series_element->getAttribute("x")); x_vec = GRM::get>((*context)[x]); - x_length = (int)x_vec.size(); + x_length = static_cast(x_vec.size()); /* get all points for the fill area from the current line */ x1 = (int_lim_low < x_vec[0]) ? x_vec[0] - x_shift : int_lim_low - x_shift; f1.push_back(x1); - f2.push_back((static_cast(subplot_element->getAttribute("y_log"))) ? 1 : 0); + f2.push_back(static_cast(plot_element->getAttribute("y_log")) ? 1 : 0); for (i = 0; i < x_length; i++) { if (grm_isnan(x_vec[i]) || grm_isnan(y_vec[i])) continue; @@ -3573,7 +3601,7 @@ static void processIntegral(const std::shared_ptr &element, const } x2 = (x_vec[x_length - 1] < int_lim_high) ? x_vec[x_length - 1] - x_shift : int_lim_high - x_shift; f1.push_back(x2); - f2.push_back((static_cast(subplot_element->getAttribute("y_log"))) ? 1 : 0); + f2.push_back((static_cast(plot_element->getAttribute("y_log"))) ? 1 : 0); id = static_cast(global_root->getAttribute("_id")); global_root->setAttribute("_id", id + 1); @@ -3674,10 +3702,9 @@ static void processIntegralGroup(const std::shared_ptr &element, std::vector int_limits_high_vec, int_limits_low_vec; int limits_high_num = 0, limits_low_num = 0; del_values del = del_values::update_without_default; - int child_id = 0, id, i; + int child_id = 0; std::shared_ptr integral; std::string str; - auto subplot_element = getSubplotElement(element); del = del_values(static_cast(element->getAttribute("_delete_children"))); clearOldChildren(&del, element); @@ -3696,7 +3723,7 @@ static void processIntegralGroup(const std::shared_ptr &element, if (limits_low_num != limits_high_num) throw std::length_error("Both limits must have the same number of arguments"); /* create or update all the children */ - for (i = 0; i < limits_low_num; i++) + for (int i = 0; i < limits_low_num; i++) { if ((del != del_values::update_without_default && del != del_values::update_with_default)) { @@ -3808,7 +3835,7 @@ static void processMarginalHeatmapKind(const std::shared_ptr &elem for (i = 2; i < 2 * len; i += 2) { x_step_boundaries[i - 1] = x_step_boundaries[i] = - x_step_boundaries[0] + (i / 2) * ((location == "right") ? (ymax - ymin) : (xmax - xmin)) / len; + x_step_boundaries[0] + int(i / 2) * ((location == "right") ? (ymax - ymin) : (xmax - xmin)) / len; } x_step_boundaries[2 * len - 1] = (location == "right") ? ymax : xmax; y_step_values[0] = y[0]; @@ -3923,28 +3950,15 @@ static void processMarginalHeatmapKind(const std::shared_ptr &elem bool is_horizontal = static_cast(series->getAttribute("orientation")) == "horizontal"; std::vector> bar_groups = series->children(); - if ((is_horizontal && x_ind == -1) || (!is_horizontal && y_ind == -1)) - { - continue; - } - if ((is_horizontal ? x_ind : y_ind) >= bar_groups.size()) - { - continue; - } + if ((is_horizontal && x_ind == -1) || (!is_horizontal && y_ind == -1)) continue; + if ((is_horizontal ? x_ind : y_ind) >= bar_groups.size()) continue; for (const auto &group : bar_groups) { for (const auto &rect : group->children()) { if (rect->hasAttribute("line_color_ind")) continue; - if (cnt == (is_horizontal ? x_ind : y_ind)) - { - rect->setAttribute("fill_color_ind", 2); - } - else - { - rect->setAttribute("fill_color_ind", 989); - } + rect->setAttribute("fill_color_ind", (cnt == (is_horizontal ? x_ind : y_ind)) ? 2 : 989); cnt += 1; } } @@ -3976,12 +3990,12 @@ void GRM::Render::processLimits(const std::shared_ptr &element) int scale = 0; bool plot_reset_ranges = false; std::shared_ptr central_region; - auto kind = static_cast(element->getAttribute("kind")); + const auto kind = static_cast(element->getAttribute("_kind")); gr_inqscale(&scale); - if (kind != "pie" && kind != "polar" && kind != "polar_histogram" && kind != "polar_heatmap" && - kind != "nonuniformpolar_heatmap") + if (kind != "pie" && polar_kinds.count(kind) <= 0) { + // doens't work for polar-plots cause the set window isn't the 'real' window scale |= static_cast(element->getAttribute("x_log")) ? GR_OPTION_X_LOG : 0; scale |= static_cast(element->getAttribute("y_log")) ? GR_OPTION_Y_LOG : 0; scale |= static_cast(element->getAttribute("z_log")) ? GR_OPTION_Z_LOG : 0; @@ -4198,16 +4212,15 @@ std::string lineTypeIntToString(int line_type) { for (auto const &map_elem : line_type_string_to_int) { - if (map_elem.second == line_type) - { - return map_elem.first; - } + if (map_elem.second == line_type) return map_elem.first; } + logger((stderr, "Got unknown line type \"%i\"\n", line_type)); + throw std::logic_error("The given line type is unknown.\n"); } static void processLineType(const std::shared_ptr &element) { - int line_type; + int line_type = 1; if (element->getAttribute("line_type").isInt()) { line_type = static_cast(element->getAttribute("line_type")); @@ -4243,16 +4256,15 @@ std::string markerTypeIntToString(int marker_type) { for (auto const &map_elem : marker_type_string_to_int) { - if (map_elem.second == marker_type) - { - return map_elem.first; - } + if (map_elem.second == marker_type) return map_elem.first; } + logger((stderr, "Got unknown marker type \"%i\"\n", marker_type)); + throw std::logic_error("The given marker type is unknown.\n"); } static void processMarkerType(const std::shared_ptr &element) { - int marker_type; + int marker_type = 1; if (element->getAttribute("marker_type").isInt()) { marker_type = static_cast(element->getAttribute("marker_type")); @@ -4272,6 +4284,8 @@ int projectionTypeStringToInt(const std::string &projection_type_str) return 1; else if (projection_type_str == "perspective") return 2; + logger((stderr, "Got unknown projection type \"%s\"\n", projection_type_str.c_str())); + throw std::logic_error("The given projection type is unknown.\n"); } std::string projectionTypeIntToString(int projection_type) @@ -4282,11 +4296,13 @@ std::string projectionTypeIntToString(int projection_type) return "orthographic"; else if (projection_type == 2) return "perspective"; + logger((stderr, "Got unknown projection type \"%i\"\n", projection_type)); + throw std::logic_error("The given projection type is unknown.\n"); } static void processProjectionType(const std::shared_ptr &element) { - int projection_type; + int projection_type = 0; if (element->getAttribute("projection_type").isInt()) { projection_type = static_cast(element->getAttribute("projection_type")); @@ -4300,20 +4316,21 @@ static void processProjectionType(const std::shared_ptr &element) static void processRelativeCharHeight(const std::shared_ptr &element) { - double viewport[4], subplot_viewport[4]; - auto plot_element = getSubplotElement(element); - double char_height, max_char_height, max_char_height_rel; - std::shared_ptr central_region_parent, subplot_parent; - auto kind = static_cast(plot_element->getAttribute("kind")); + double viewport[4]; + double figure_viewport[4]; // figure vp unless there are more plots inside a figure; then it's the vp for each plot + auto plot_element = getPlotElement(element); + double max_char_height, max_char_height_rel; + std::shared_ptr figure_vp_element; + auto kind = static_cast(plot_element->getAttribute("_kind")); double diag_factor; double metric_width, metric_height; - bool multiple_plots = false, uniform_data = true, keep_aspect_ratio = false, only_quadratic_aspect_ratio = false; + std::string location; + bool uniform_data = true, keep_aspect_ratio = false, only_quadratic_aspect_ratio = false; - subplot_parent = (plot_element->parentElement()->localName() == "layout_grid_element") - ? subplot_parent = plot_element->parentElement() - : plot_element; - central_region_parent = plot_element; - if (kind == "marginal_heatmap") central_region_parent = plot_element->children()[0]; + // special case where the figure vp is not stored inside the plot element + figure_vp_element = (plot_element->parentElement()->localName() == "layout_grid_element") + ? figure_vp_element = plot_element->parentElement() + : plot_element; if (!element->parentElement()->hasAttribute("viewport_x_min") || !element->parentElement()->hasAttribute("viewport_x_max") || @@ -4331,13 +4348,14 @@ static void processRelativeCharHeight(const std::shared_ptr &eleme max_char_height = static_cast(element->getAttribute("max_char_height")); keep_aspect_ratio = static_cast(plot_element->getAttribute("keep_aspect_ratio")); only_quadratic_aspect_ratio = static_cast(plot_element->getAttribute("only_quadratic_aspect_ratio")); + location = static_cast(element->parentElement()->parentElement()->getAttribute("location")); - subplot_viewport[0] = static_cast(subplot_parent->getAttribute("plot_x_min")); - subplot_viewport[1] = static_cast(subplot_parent->getAttribute("plot_x_max")); - subplot_viewport[2] = - static_cast(subplot_parent->getAttribute("plot_y_min")) / (DEFAULT_ASPECT_RATIO_FOR_SCALING); - subplot_viewport[3] = - static_cast(subplot_parent->getAttribute("plot_y_max")) / (DEFAULT_ASPECT_RATIO_FOR_SCALING); + figure_viewport[0] = static_cast(figure_vp_element->getAttribute("plot_x_min")); + figure_viewport[1] = static_cast(figure_vp_element->getAttribute("plot_x_max")); + figure_viewport[2] = + static_cast(figure_vp_element->getAttribute("plot_y_min")) / (DEFAULT_ASPECT_RATIO_FOR_SCALING); + figure_viewport[3] = + static_cast(figure_vp_element->getAttribute("plot_y_max")) / (DEFAULT_ASPECT_RATIO_FOR_SCALING); GRM::Render::getFigureSize(nullptr, nullptr, &metric_width, &metric_height); auto aspect_ratio_ws = metric_width / metric_height; @@ -4357,37 +4375,41 @@ static void processRelativeCharHeight(const std::shared_ptr &eleme if (uniform_data) { double border = - 0.5 * (subplot_viewport[1] - subplot_viewport[0]) * (1.0 - 1.0 / (DEFAULT_ASPECT_RATIO_FOR_SCALING)); - subplot_viewport[0] += border; - subplot_viewport[1] -= border; + 0.5 * (figure_viewport[1] - figure_viewport[0]) * (1.0 - 1.0 / (DEFAULT_ASPECT_RATIO_FOR_SCALING)); + figure_viewport[0] += border; + figure_viewport[1] -= border; } } if ((keep_aspect_ratio && uniform_data && only_quadratic_aspect_ratio) || !keep_aspect_ratio) { // calculate the diagonal viewport size of the default viewport with the fix aspect_ratio 4/3 - calculateCentralRegionMarginOrDiagFactor(element, &subplot_viewport[0], &subplot_viewport[1], - &subplot_viewport[2], &subplot_viewport[3], true); - diag_factor = - std::sqrt((subplot_viewport[1] - subplot_viewport[0]) * (subplot_viewport[1] - subplot_viewport[0]) + - (subplot_viewport[3] - subplot_viewport[2]) * (subplot_viewport[3] - subplot_viewport[2])); + calculateCentralRegionMarginOrDiagFactor(element, &figure_viewport[0], &figure_viewport[1], &figure_viewport[2], + &figure_viewport[3], true); + diag_factor = std::sqrt((figure_viewport[1] - figure_viewport[0]) * (figure_viewport[1] - figure_viewport[0]) + + (figure_viewport[3] - figure_viewport[2]) * (figure_viewport[3] - figure_viewport[2])); } else { double default_diag_factor; diag_factor = std::sqrt((viewport[1] - viewport[0]) * (viewport[1] - viewport[0]) + (viewport[3] - viewport[2]) * (viewport[3] - viewport[2])); + // adjustment especially for horizontal colorbars where the char_height otherwise would be to big + if (location == "bottom" || location == "top") + diag_factor *= (figure_viewport[3] - figure_viewport[2]); + else if (location == "left" || location == "right") + diag_factor *= (figure_viewport[1] - figure_viewport[0]); if (element->hasAttribute("_default_diag_factor")) { default_diag_factor = static_cast(element->getAttribute("_default_diag_factor")); } else { - calculateCentralRegionMarginOrDiagFactor(element, &subplot_viewport[0], &subplot_viewport[1], - &subplot_viewport[2], &subplot_viewport[3], true); + calculateCentralRegionMarginOrDiagFactor(element, &figure_viewport[0], &figure_viewport[1], + &figure_viewport[2], &figure_viewport[3], true); double plot_diag_factor = - std::sqrt((subplot_viewport[1] - subplot_viewport[0]) * (subplot_viewport[1] - subplot_viewport[0]) + - (subplot_viewport[3] - subplot_viewport[2]) * (subplot_viewport[3] - subplot_viewport[2])); + std::sqrt((figure_viewport[1] - figure_viewport[0]) * (figure_viewport[1] - figure_viewport[0]) + + (figure_viewport[3] - figure_viewport[2]) * (figure_viewport[3] - figure_viewport[2])); auto start_aspect_ratio_ws = static_cast(plot_element->getAttribute("_start_aspect_ratio")); default_diag_factor = ((DEFAULT_ASPECT_RATIO_FOR_SCALING) * (start_aspect_ratio_ws <= 1 ? start_aspect_ratio_ws : (1.0 / start_aspect_ratio_ws))) * @@ -4461,12 +4483,12 @@ static void processSelectSpecificXform(const std::shared_ptr &elem static void processSpace(const std::shared_ptr &element) { - auto zmin = static_cast(element->getAttribute("space_z_min")); - auto zmax = static_cast(element->getAttribute("space_z_max")); + auto z_min = static_cast(element->getAttribute("space_z_min")); + auto z_max = static_cast(element->getAttribute("space_z_max")); auto rotation = static_cast(element->getAttribute("space_rotation")); auto tilt = static_cast(element->getAttribute("space_tilt")); - gr_setspace(zmin, zmax, rotation, tilt); + gr_setspace(z_min, z_max, rotation, tilt); } static void processSpace3d(const std::shared_ptr &element) @@ -4504,11 +4526,10 @@ std::string locationIntToString(int location) { for (auto const &map_elem : location_string_to_int) { - if (map_elem.second == location) - { - return map_elem.first; - } + if (map_elem.second == location) return map_elem.first; } + logger((stderr, "Got unknown location \"%i\"\n", location)); + throw std::logic_error("The given location is unknown.\n"); } int modelStringToInt(const std::string &model_str) @@ -4520,11 +4541,10 @@ std::string modelIntToString(int model) { for (auto const &map_elem : model_string_to_int) { - if (map_elem.second == model) - { - return map_elem.first; - } + if (map_elem.second == model) return map_elem.first; } + logger((stderr, "Got unknown model \"%i\"\n", model)); + throw std::logic_error("The given model is unknown.\n"); } int textAlignHorizontalStringToInt(const std::string &text_align_horizontal_str) @@ -4536,11 +4556,10 @@ std::string textAlignHorizontalIntToString(int text_align_horizontal) { for (auto const &map_elem : text_align_horizontal_string_to_int) { - if (map_elem.second == text_align_horizontal) - { - return map_elem.first; - } + if (map_elem.second == text_align_horizontal) return map_elem.first; } + logger((stderr, "Got unknown horizontal text aligment \"%i\"\n", text_align_horizontal)); + throw std::logic_error("The given horizontal text aligment is unknown.\n"); } int textAlignVerticalStringToInt(const std::string &text_align_vertical_str) @@ -4552,16 +4571,15 @@ std::string textAlignVerticalIntToString(int text_align_vertical) { for (auto const &map_elem : text_align_vertical_string_to_int) { - if (map_elem.second == text_align_vertical) - { - return map_elem.first; - } + if (map_elem.second == text_align_vertical) return map_elem.first; } + logger((stderr, "Got unknown vertical text aligment \"%i\"\n", text_align_vertical)); + throw std::logic_error("The given vertical text aligment is unknown.\n"); } static void processTextAlign(const std::shared_ptr &element) { - int text_align_vertical, text_align_horizontal; + int text_align_vertical = 0, text_align_horizontal = 0; if (element->getAttribute("text_align_vertical").isInt()) { text_align_vertical = static_cast(element->getAttribute("text_align_vertical")); @@ -4595,29 +4613,25 @@ static void processTextColorForBackground(const std::shared_ptr &e plot: for which plot it is used: right now only pie plot */ { - int color_ind, inq_color; + int color_ind; unsigned char color_rgb[4]; std::string plot = "pie"; std::shared_ptr plot_parent = element; getPlotParent(plot_parent); if (!static_cast(element->getAttribute("set_text_color_for_background"))) return; - if (element->hasAttribute("stcfb_plot")) - { - plot = static_cast(element->getAttribute("stcfb_plot")); - } + if (element->hasAttribute("stcfb_plot")) plot = static_cast(element->getAttribute("stcfb_plot")); - if (plot == "pie" && static_cast(plot_parent->getAttribute("kind")) == "pie") + if (plot == "pie" && static_cast(plot_parent->getAttribute("_kind")) == "pie") { double r, g, b; double color_lightness; + int text_color_ind = 1; std::shared_ptr render; render = std::dynamic_pointer_cast(element->ownerDocument()); - if (!render) - { - throw NotFoundError("Render-document not found for element\n"); - } + if (!render) throw NotFoundError("Render-document not found for element\n"); + if (element->hasAttribute("color_ind")) { color_ind = static_cast(element->getAttribute("color_ind")); @@ -4633,22 +4647,14 @@ static void processTextColorForBackground(const std::shared_ptr &e b = color_rgb[2] / 255.0; color_lightness = getLightnessFromRGB(r, g, b); - if (color_lightness < 0.4) - { - gr_settextcolorind(0); - element->setAttribute("text_color_ind", 0); - } - else - { - gr_settextcolorind(1); - element->setAttribute("text_color_ind", 1); - } + if (color_lightness < 0.4) text_color_ind = 0; + gr_settextcolorind(text_color_ind); + element->setAttribute("text_color_ind", text_color_ind); } } static void processTextColorInd(const std::shared_ptr &element) { - gr_settextcolorind(static_cast(element->getAttribute("text_color_ind"))); } @@ -4658,6 +4664,8 @@ int textEncodingStringToInt(const std::string &text_encoding_str) return 300; else if (text_encoding_str == "utf8") return 301; + logger((stderr, "Got unknown text encoding \"%s\"\n", text_encoding_str.c_str())); + throw std::logic_error("The given text encoding is unknown.\n"); } std::string textEncodingIntToString(int text_encoding) @@ -4666,11 +4674,13 @@ std::string textEncodingIntToString(int text_encoding) return "latin1"; else if (text_encoding == 301) return "utf8"; + logger((stderr, "Got unknown text encoding \"%i\"\n", text_encoding)); + throw std::logic_error("The given text encoding is unknown.\n"); } static void processTextEncoding(const std::shared_ptr &element) { - int text_encoding; + int text_encoding = 301; if (element->getAttribute("text_encoding").isInt()) { text_encoding = static_cast(element->getAttribute("text_encoding")); @@ -4688,6 +4698,8 @@ int tickOrientationStringToInt(const std::string &tick_orientation_str) return 1; else if (tick_orientation_str == "down") return -1; + logger((stderr, "Got unknown tick orientation \"%s\"\n", tick_orientation_str.c_str())); + throw std::logic_error("The given tick orientation is unknown.\n"); } std::string tickOrientationIntToString(int tick_orientation) @@ -4696,6 +4708,8 @@ std::string tickOrientationIntToString(int tick_orientation) return "up"; else if (tick_orientation < 0) return "down"; + logger((stderr, "Got unknown tick orientation \"%i\"\n", tick_orientation)); + throw std::logic_error("The given tick orientation is unknown.\n"); } static void processTransparency(const std::shared_ptr &element) @@ -4715,7 +4729,7 @@ static void axisArgumentsConvertedIntoTickGroups(tick_t *ticks, tick_label_t *ti if (static_cast(axis->getAttribute("mirrored_axis"))) child_id += 1; for (int i = 0; i < num_ticks; i++) { - std::string label = ""; + std::string label; double width = 0.0; if (label_ind < num_labels && tick_labels[label_ind].tick == ticks[i].value) { @@ -4750,7 +4764,7 @@ static void processAxis(const std::shared_ptr &element, const std: double x_tick, x_org; double y_tick, y_org; int x_major, y_major, major_count = 1; - int tick_orientation = 1, child_id = 0; + int tick_orientation = 1; double tick_size = NAN, tick = NAN; double min_val = NAN, max_val = NAN; double org = NAN, pos = NAN; @@ -4785,10 +4799,10 @@ static void processAxis(const std::shared_ptr &element, const std: element->setAttribute("_window_old_y_min", window[2]); element->setAttribute("_window_old_y_max", window[3]); - kind = static_cast(plot_parent->getAttribute("kind")); + kind = static_cast(plot_parent->getAttribute("_kind")); if (element->hasAttribute("mirrored_axis")) mirrored_axis = static_cast(element->getAttribute("mirrored_axis")); axis_type = static_cast(element->getAttribute("axis_type")); - if (element->hasAttribute("scientific_format")) // TODO: maybe need to be changed if Du Kim's MR gets merged + if (element->hasAttribute("scientific_format")) scientific_format = static_cast(element->getAttribute("scientific_format")); if (plot_parent->hasAttribute("font")) processFont(plot_parent); if (plot_parent->hasAttribute("x_flip")) x_flip = static_cast(plot_parent->getAttribute("x_flip")); @@ -4846,7 +4860,7 @@ static void processAxis(const std::shared_ptr &element, const std: for (const auto &series : central_region->children()) { if (starts_with(series->localName(), "series_") && - str_equals_any(series->localName(), "series_heatmap", "series_shade")) + str_equals_any(series->localName(), "series_contourf", "series_heatmap", "series_shade")) { tick_orientation = -1; break; @@ -4855,7 +4869,10 @@ static void processAxis(const std::shared_ptr &element, const std: } else { - if ((scale & GR_OPTION_FLIP_X || x_flip) && axis_type == "y") pos = window[0]; + auto location = static_cast( + element->parentElement()->parentElement()->parentElement()->getAttribute("location")); + if ((scale & GR_OPTION_FLIP_X || x_flip) && axis_type == "y" && location == "right") pos = window[0]; + if ((scale & GR_OPTION_FLIP_Y || y_flip) && axis_type == "x" && location == "top") pos = window[2]; processFlip(element->parentElement()); } tick_size *= tick_orientation; @@ -4986,19 +5003,9 @@ void GRM::Render::processWindow(const std::shared_ptr &element) { std::shared_ptr plot_element = element; getPlotParent(plot_element); - auto kind = static_cast(plot_element->getAttribute("kind")); + auto kind = static_cast(plot_element->getAttribute("_kind")); - if (str_equals_any(kind, "polar", "polar_histogram", "polar_heatmap", "nonuniformpolar_heatmap")) - { - gr_setwindow(-1, 1, -1, 1); - } - else - { - if (kind != "pie") - { - if (xmax - xmin > 0.0 && ymax - ymin > 0.0) gr_setwindow(xmin, xmax, ymin, ymax); - } - } + if (kind != "pie" && xmax - xmin > 0.0 && ymax - ymin > 0.0) gr_setwindow(xmin, xmax, ymin, ymax); if (str_equals_any(kind, "wireframe", "surface", "plot3", "scatter3", "trisurface", "volume", "isosurface")) { auto zmin = static_cast(element->getAttribute("window_z_min")); @@ -5008,11 +5015,19 @@ void GRM::Render::processWindow(const std::shared_ptr &element) } if (element->hasAttribute("_zoomed") && static_cast(element->getAttribute("_zoomed"))) { - for (const auto axis : element->querySelectorsAll("axis")) + for (const auto &axis : element->querySelectorsAll("axis")) { clearAxisAttributes(axis); processAxis(axis, global_render->context); } + for (const auto &axis : element->querySelectorsAll("rho_axes")) + { + processRhoAxes(axis, global_render->context); + } + for (const auto &axis : element->querySelectorsAll("theta_axes")) + { + processThetaAxes(axis, global_render->context); + } element->setAttribute("_zoomed", false); } } @@ -5078,29 +5093,30 @@ void GRM::Render::calculateCharHeight(const std::shared_ptr &eleme * \param[in] element The GRM::Element that contains the attributes */ double viewport[4]; - double subplot_viewport[4]; // the subplot vp is the figure vp unless there are more plots inside a figure + double figure_viewport[4]; // figure vp unless there are more plots inside a figure; then it's the vp for each plot double char_height, diag_factor; std::string kind; double metric_width, metric_height; bool keep_aspect_ratio = false, uniform_data = true, only_quadratic_aspect_ratio = false; - std::shared_ptr plot_parent = element, subplot_parent; + std::shared_ptr plot_parent = element, figure_vp_element; getPlotParent(plot_parent); - subplot_parent = (plot_parent->parentElement()->localName() == "layout_grid_element") - ? subplot_parent = plot_parent->parentElement() - : plot_parent; + // special case where the figure vp is not stored inside the plot element + figure_vp_element = (plot_parent->parentElement()->localName() == "layout_grid_element") + ? figure_vp_element = plot_parent->parentElement() + : plot_parent; viewport[0] = static_cast(element->getAttribute("viewport_x_min")); viewport[1] = static_cast(element->getAttribute("viewport_x_max")); viewport[2] = static_cast(element->getAttribute("viewport_y_min")); viewport[3] = static_cast(element->getAttribute("viewport_y_max")); - subplot_viewport[0] = static_cast(subplot_parent->getAttribute("plot_x_min")); - subplot_viewport[1] = static_cast(subplot_parent->getAttribute("plot_x_max")); - subplot_viewport[2] = - static_cast(subplot_parent->getAttribute("plot_y_min")) / (DEFAULT_ASPECT_RATIO_FOR_SCALING); - subplot_viewport[3] = - static_cast(subplot_parent->getAttribute("plot_y_max")) / (DEFAULT_ASPECT_RATIO_FOR_SCALING); - kind = static_cast(plot_parent->getAttribute("kind")); + figure_viewport[0] = static_cast(figure_vp_element->getAttribute("plot_x_min")); + figure_viewport[1] = static_cast(figure_vp_element->getAttribute("plot_x_max")); + figure_viewport[2] = + static_cast(figure_vp_element->getAttribute("plot_y_min")) / (DEFAULT_ASPECT_RATIO_FOR_SCALING); + figure_viewport[3] = + static_cast(figure_vp_element->getAttribute("plot_y_max")) / (DEFAULT_ASPECT_RATIO_FOR_SCALING); + kind = static_cast(plot_parent->getAttribute("_kind")); keep_aspect_ratio = static_cast(plot_parent->getAttribute("keep_aspect_ratio")); only_quadratic_aspect_ratio = static_cast(plot_parent->getAttribute("only_quadratic_aspect_ratio")); @@ -5122,20 +5138,19 @@ void GRM::Render::calculateCharHeight(const std::shared_ptr &eleme if (uniform_data) { double border = - 0.5 * (subplot_viewport[1] - subplot_viewport[0]) * (1.0 - 1.0 / (DEFAULT_ASPECT_RATIO_FOR_SCALING)); - subplot_viewport[0] += border; - subplot_viewport[1] -= border; + 0.5 * (figure_viewport[1] - figure_viewport[0]) * (1.0 - 1.0 / (DEFAULT_ASPECT_RATIO_FOR_SCALING)); + figure_viewport[0] += border; + figure_viewport[1] -= border; } } if ((keep_aspect_ratio && uniform_data && only_quadratic_aspect_ratio) || !keep_aspect_ratio) { // calculate the diagonal viewport size of the default viewport with the fix aspect_ratio 4/3 - calculateCentralRegionMarginOrDiagFactor(element, &subplot_viewport[0], &subplot_viewport[1], - &subplot_viewport[2], &subplot_viewport[3], true); - diag_factor = - std::sqrt((subplot_viewport[1] - subplot_viewport[0]) * (subplot_viewport[1] - subplot_viewport[0]) + - (subplot_viewport[3] - subplot_viewport[2]) * (subplot_viewport[3] - subplot_viewport[2])); + calculateCentralRegionMarginOrDiagFactor(element, &figure_viewport[0], &figure_viewport[1], &figure_viewport[2], + &figure_viewport[3], true); + diag_factor = std::sqrt((figure_viewport[1] - figure_viewport[0]) * (figure_viewport[1] - figure_viewport[0]) + + (figure_viewport[3] - figure_viewport[2]) * (figure_viewport[3] - figure_viewport[2])); } else { @@ -5143,11 +5158,11 @@ void GRM::Render::calculateCharHeight(const std::shared_ptr &eleme (viewport[3] - viewport[2]) * (viewport[3] - viewport[2])); if (!element->hasAttribute("_default_diag_factor")) { - calculateCentralRegionMarginOrDiagFactor(element, &subplot_viewport[0], &subplot_viewport[1], - &subplot_viewport[2], &subplot_viewport[3], true); + calculateCentralRegionMarginOrDiagFactor(element, &figure_viewport[0], &figure_viewport[1], + &figure_viewport[2], &figure_viewport[3], true); double plot_diag_factor = - std::sqrt((subplot_viewport[1] - subplot_viewport[0]) * (subplot_viewport[1] - subplot_viewport[0]) + - (subplot_viewport[3] - subplot_viewport[2]) * (subplot_viewport[3] - subplot_viewport[2])); + std::sqrt((figure_viewport[1] - figure_viewport[0]) * (figure_viewport[1] - figure_viewport[0]) + + (figure_viewport[3] - figure_viewport[2]) * (figure_viewport[3] - figure_viewport[2])); auto start_aspect_ratio_ws = static_cast(plot_parent->getAttribute("_start_aspect_ratio")); double default_diag_factor = ((DEFAULT_ASPECT_RATIO_FOR_SCALING) * @@ -5164,7 +5179,7 @@ void GRM::Render::calculateCharHeight(const std::shared_ptr &eleme { char_height = PLOT_3D_CHAR_HEIGHT; } - else if (str_equals_any(kind, "polar", "polar_histogram", "polar_heatmap", "nonuniformpolar_heatmap")) + else if (polar_kinds.count(kind) > 0) { char_height = PLOT_POLAR_CHAR_HEIGHT; } @@ -5253,6 +5268,7 @@ void GRM::Render::processAttributes(const std::shared_ptr &element {std::string("char_expan"), processCharExpan}, {std::string("char_space"), processCharSpace}, {std::string("char_up_x"), processCharUp}, // the x element can be used cause both must be set + {std::string("clip_region"), processClipRegion}, {std::string("clip_transformation"), processClipTransformation}, {std::string("colormap"), processColormap}, {std::string("fill_color_ind"), processFillColorInd}, @@ -5295,8 +5311,7 @@ void GRM::Render::processAttributes(const std::shared_ptr &element static std::map &, const std::string attribute)>> multiAttrStringToFunc{ - /* This map contains functions for attributes of which an element can hold more than one e.g. colorrep - * */ + /* This map contains functions for attributes of which an element can hold more than one e.g. colorrep */ {std::string("colorrep"), processColorRep}, }; @@ -5304,14 +5319,11 @@ void GRM::Render::processAttributes(const std::shared_ptr &element { auto start = 0U; auto end = attribute.find('.'); - if (end != std::string::npos) + if (end != std::string::npos) /* element can hold more than one attribute of this kind */ { - /* element can hold more than one attribute of this kind */ auto attributeKind = attribute.substr(start, end); if (multiAttrStringToFunc.find(attributeKind) != multiAttrStringToFunc.end()) - { - multiAttrStringToFunc[attributeKind](element, attribute); - } + multiAttrStringToFunc[attributeKind](element, attribute); } else if (attrStringToFunc.find(attribute) != attrStringToFunc.end()) { @@ -5319,15 +5331,9 @@ void GRM::Render::processAttributes(const std::shared_ptr &element } } - for (auto &attribute : element->getAttributeNames()) - /* - * Post process attribute run - */ + for (auto &attribute : element->getAttributeNames()) // Post process attribute run { - if (attrStringToFuncPost.find(attribute) != attrStringToFuncPost.end()) - { - attrStringToFuncPost[attribute](element); - } + if (attrStringToFuncPost.find(attribute) != attrStringToFuncPost.end()) attrStringToFuncPost[attribute](element); } } @@ -5336,17 +5342,17 @@ void GRM::Render::processAttributes(const std::shared_ptr &element static void drawYLine(const std::shared_ptr &element, const std::shared_ptr &context) { double window[4]; - double ymin; + double ymin = 0, series_y_min = DBL_MAX; double line_x1, line_x2, line_y1, line_y2; std::shared_ptr series = nullptr, line, central_region, central_region_parent; std::string orientation = PLOT_DEFAULT_ORIENTATION; del_values del = del_values::update_without_default; - auto subplot_element = getSubplotElement(element); - auto kind = static_cast(subplot_element->getAttribute("kind")); + auto plot_element = getPlotElement(element); + auto kind = static_cast(plot_element->getAttribute("_kind")); - central_region_parent = subplot_element; - if (kind == "marginal_heatmap") central_region_parent = subplot_element->children()[0]; + central_region_parent = plot_element; + if (kind == "marginal_heatmap") central_region_parent = plot_element->children()[0]; for (const auto &child : central_region_parent->children()) { if (child->localName() == "central_region") @@ -5361,12 +5367,36 @@ static void drawYLine(const std::shared_ptr &element, const std::s window[2] = static_cast(central_region->getAttribute("window_y_min")); window[3] = static_cast(central_region->getAttribute("window_y_max")); + auto y_log = plot_element->hasAttribute("y_log") && static_cast(plot_element->getAttribute("y_log")); for (const auto &child : central_region->children()) { if (child->localName() != "series_barplot" && child->localName() != "series_stem") continue; - series = child; - break; + if (series == nullptr) series = child; + if (child->hasAttribute("y_range_min")) + { + if (y_log) + { + series_y_min = grm_min(series_y_min, static_cast(child->getAttribute("y_range_min"))); + } + else + { + auto y_min = static_cast(child->getAttribute("y_range_min")); + if (series_y_min == DBL_MAX) series_y_min = y_min; + series_y_min = grm_min(series_y_min, y_min); + } + } + } + if (series_y_min != DBL_MAX) ymin = series_y_min; + if (plot_element->hasAttribute("_y_line_pos")) ymin = static_cast(plot_element->getAttribute("_y_line_pos")); + if (ymin <= 0 && y_log) + { + ymin = 1; + if (series_y_min > 0) ymin = grm_min(ymin, series_y_min); } + bool grplot = plot_element->hasAttribute("grplot") ? static_cast(plot_element->getAttribute("grplot")) : false; + if (series != nullptr && series->localName() == "series_barplot" && ymin < 0 && !grplot && + static_cast(series->getAttribute("style")) == "stacked") + ymin = 0; if (series != nullptr) { @@ -5378,10 +5408,7 @@ static void drawYLine(const std::shared_ptr &element, const std::s { series->setAttribute("orientation", orientation); } - - if (series->hasAttribute("y_range_min")) ymin = static_cast(series->getAttribute("y_range_min")); } - if (series != nullptr && series->localName() == "series_barplot" && ymin < 0) ymin = 0; bool is_vertical = orientation == "vertical"; @@ -5441,12 +5468,8 @@ static void processAxes3d(const std::shared_ptr &element, const st getAxes3dInformation(element, x_org_pos, y_org_pos, z_org_pos, x_org, y_org, z_org, x_major, y_major, z_major, x_tick, y_tick, z_tick); - auto subplot_element = getSubplotElement(element); - if (element->hasAttribute("tick_orientation")) - { - tick_orientation = static_cast(element->getAttribute("tick_orientation")); - } + tick_orientation = static_cast(element->getAttribute("tick_orientation")); getTickSize(element, tick_size); tick_size *= tick_orientation; @@ -5458,7 +5481,7 @@ static void processAxes3d(const std::shared_ptr &element, const st static void processCellArray(const std::shared_ptr &element, const std::shared_ptr &context) { /*! - * Processing function for cellArray + * Processing function for cell_array * * \param[in] element The GRM::Element that contains the attributes and data keys * \param[in] context The GRM::Context that contains the actual data @@ -5482,28 +5505,33 @@ static void processCellArray(const std::shared_ptr &element, const static void processColorbar(const std::shared_ptr &element, const std::shared_ptr &context) { - double c_min, c_max; - int data, i, options; + double c_min, c_max, x_min = 0.0, x_max = 1.0; + int data, i, options, dim_x = 1; int z_log = 0; - int child_id = 0; + std::string location, axis_type = "y"; del_values del = del_values::update_without_default; - std::shared_ptr cell_array = nullptr, axis = nullptr; + std::shared_ptr cell_array = nullptr, axis_elem = nullptr; auto colors = static_cast(element->getAttribute("color_ind")); - - if (!getLimitsForColorbar(element, c_min, c_max)) - { - auto subplot_element = getSubplotElement(element); - if (!getLimitsForColorbar(subplot_element, c_min, c_max)) - { - throw NotFoundError("Missing limits\n"); - } - } - auto plot_parent = element->parentElement(); getPlotParent(plot_parent); + + if (!getLimitsForColorbar(element, c_min, c_max) && !getLimitsForColorbar(plot_parent, c_min, c_max)) + throw NotFoundError("Missing limits\n"); + z_log = static_cast(plot_parent->getAttribute("z_log")); - global_render->setWindow(element->parentElement(), 0.0, 1.0, c_min, c_max); - gr_setwindow(0.0, 1.0, c_min, c_max); + location = static_cast(element->parentElement()->parentElement()->getAttribute("location")); + + if (location == "top" || location == "bottom") + { + // swap x and y if the colorbar is in the bottom or top side_region + x_min = c_min; + x_max = c_max; + c_min = 0.0; + c_max = 1.0; + axis_type = "x"; + } + global_render->setWindow(element->parentElement(), x_min, x_max, c_min, c_max); + global_render->processWindow(element->parentElement()); calculateViewport(element); applyMoveTransformation(element); @@ -5523,112 +5551,189 @@ static void processColorbar(const std::shared_ptr &element, const del = del_values(static_cast(element->getAttribute("_delete_children"))); clearOldChildren(&del, element); + if (location == "top" || location == "bottom") + { + // now swap also the shape of the data for x and y + dim_x = colors; + colors = 1; + } + if (del != del_values::update_without_default && del != del_values::update_with_default) { - cell_array = - global_render->createCellArray(0, 1, c_max, c_min, 1, colors, 1, 1, 1, colors, "data" + str, data_vec); + cell_array = global_render->createCellArray(x_min, x_max, c_max, c_min, dim_x, colors, 1, 1, dim_x, colors, + "data" + str, data_vec); cell_array->setAttribute("_child_id", 0); element->append(cell_array); } else { - cell_array = element->querySelectors("cellarray[_child_id=0]"); + cell_array = element->querySelectors("cell_array[_child_id=0]"); if (cell_array != nullptr) - global_render->createCellArray(0, 1, c_max, c_min, 1, colors, 1, 1, 1, colors, "data" + str, data_vec, context, - cell_array); + global_render->createCellArray(x_min, x_max, c_max, c_min, dim_x, colors, 1, 1, dim_x, colors, "data" + str, + data_vec, context, cell_array); + } + if (cell_array != nullptr) + { + cell_array->setAttribute("name", "colorbar"); + global_render->setSelectSpecificXform(cell_array, 1); + global_render->setClipRegion(cell_array, 0); + } + + // depending on the location the position of the axis and the min and max value of the data are different + if (location == "top" || location == "bottom") + { + c_min = x_min; + c_max = x_max; + x_max = location == "top" ? 1 : 0; + } + else if (location == "left") + { + x_max = 0; } - if (cell_array != nullptr) cell_array->setAttribute("name", "colorbar"); /* create axes */ gr_inqscale(&options); if (options & GR_OPTION_Z_LOG || z_log) { - axis_t y_axis = {c_min, c_max, 2, c_min, 1, 1, 0, nullptr, NAN, 0, nullptr, NAN, 1}; - gr_axis('Y', &y_axis); + axis_t axis = {c_min, c_max, 2, c_min, x_max, 1, 0, nullptr, NAN, 0, nullptr, NAN, 1}; + if (location == "top" || location == "bottom") + gr_axis('X', &axis); + else + gr_axis('Y', &axis); - if ((del != del_values::update_without_default && del != del_values::update_with_default && axis == nullptr) || + if (location == "left" || location == "bottom") axis.tick_size *= -1.0; + + if ((del != del_values::update_without_default && del != del_values::update_with_default && + axis_elem == nullptr) || !element->hasChildNodes()) { - axis = global_render->createAxis(y_axis.min, y_axis.max, y_axis.tick, y_axis.org, y_axis.position, - y_axis.major_count, y_axis.num_ticks, y_axis.num_tick_labels, - abs(y_axis.tick_size), y_axis.tick_size > 0 ? 1 : -1, y_axis.label_position); - axis->setAttribute("_child_id", 1); - global_render->setLineColorInd(axis, 1); - element->append(axis); + axis_elem = global_render->createAxis(axis.min, axis.max, axis.tick, axis.org, axis.position, + axis.major_count, axis.num_ticks, axis.num_tick_labels, + abs(axis.tick_size), axis.tick_size > 0 ? 1 : -1, axis.label_position); + axis_elem->setAttribute("_child_id", 1); + global_render->setLineColorInd(axis_elem, 1); + element->append(axis_elem); } - else if (axis != nullptr) + else if (axis_elem != nullptr) { - axis = element->querySelectors("axis[_child_id=1]"); - if (axis != nullptr) + axis_elem = element->querySelectors("axis[_child_id=1]"); + if (axis_elem != nullptr) { - auto tick_size = y_axis.tick_size; - if (axis->hasAttribute("tick_size")) tick_size = static_cast(axis->getAttribute("tick_size")); + auto tick_size = axis.tick_size; + // change sign of tick_size depending on the location of the colorbar + if (axis_elem->hasAttribute("tick_size")) + { + tick_size = static_cast(axis_elem->getAttribute("tick_size")); + if (location == "left" || location == "bottom") + { + tick_size *= -1.0; + axis_elem->setAttribute("tick_size", tick_size); + } + } + if (axis_elem->hasAttribute("_tick_size_set_by_user")) + { + tick_size = static_cast(axis_elem->getAttribute("_tick_size_set_by_user")); + if (static_cast(axis_elem->getAttribute("axis_type")) != axis_type) + { + tick_size *= -1.0; + axis_elem->setAttribute("_tick_size_set_by_user", tick_size); + } + } - global_render->createAxis(y_axis.min, y_axis.max, y_axis.tick, y_axis.org, y_axis.position, - y_axis.major_count, y_axis.num_ticks, y_axis.num_tick_labels, abs(tick_size), - tick_size > 0 ? 1 : -1, y_axis.label_position, axis); + global_render->createAxis(axis.min, axis.max, axis.tick, axis.org, axis.position, axis.major_count, + axis.num_ticks, axis.num_tick_labels, abs(tick_size), tick_size > 0 ? 1 : -1, + axis.label_position, axis_elem); } } - if (axis != nullptr) + if (axis_elem != nullptr) { - global_render->setScale(axis, GR_OPTION_Y_LOG); - global_render->processScale(axis); - axis->setAttribute("name", "colorbar y-axis"); - axis->setAttribute("axis_type", "y"); - axis->setAttribute("draw_grid", false); - axis->setAttribute("mirrored_axis", false); - if (del == del_values::update_without_default) axis->setAttribute("min_value", c_min); + global_render->setScale(axis_elem, GR_OPTION_Y_LOG); + global_render->processScale(axis_elem); + axis_elem->setAttribute("name", "colorbar " + axis_type + "-axis"); + axis_elem->setAttribute("axis_type", axis_type); + axis_elem->setAttribute("draw_grid", false); + axis_elem->setAttribute("mirrored_axis", false); + if (del == del_values::update_without_default) axis_elem->setAttribute("min_value", c_min); } - gr_freeaxis(&y_axis); + gr_freeaxis(&axis); } else { double c_tick = autoTick(c_min, c_max); - axis_t y_axis = {c_min, c_max, c_tick, c_min, 1, 1, 0, nullptr, NAN, 0, nullptr, NAN, 1}; - gr_axis('Y', &y_axis); + axis_t axis = {c_min, c_max, c_tick, c_min, x_max, 1, 0, nullptr, NAN, 0, nullptr, NAN, 1}; + if (location == "top" || location == "bottom") + gr_axis('X', &axis); + else + gr_axis('Y', &axis); + + if (location == "left" || location == "bottom") axis.tick_size *= -1; if (del != del_values::update_without_default && del != del_values::update_with_default) { - axis = global_render->createAxis(y_axis.min, y_axis.max, y_axis.tick, y_axis.org, y_axis.position, - y_axis.major_count, y_axis.num_ticks, y_axis.num_tick_labels, - abs(y_axis.tick_size), y_axis.tick_size > 0 ? 1 : -1, y_axis.label_position); - axis->setAttribute("_child_id", 1); - global_render->setLineColorInd(axis, 1); - element->append(axis); + axis_elem = global_render->createAxis(axis.min, axis.max, axis.tick, axis.org, axis.position, + axis.major_count, axis.num_ticks, axis.num_tick_labels, + abs(axis.tick_size), axis.tick_size > 0 ? 1 : -1, axis.label_position); + axis_elem->setAttribute("_child_id", 1); + global_render->setLineColorInd(axis_elem, 1); + element->append(axis_elem); } else { - axis = element->querySelectors("axis[_child_id=1]"); - if (axis != nullptr) + axis_elem = element->querySelectors("axis[_child_id=1]"); + if (axis_elem != nullptr) { - auto tick_size = y_axis.tick_size; - if (axis->hasAttribute("tick_size")) tick_size = static_cast(axis->getAttribute("tick_size")); - global_render->createAxis(y_axis.min, y_axis.max, y_axis.tick, y_axis.org, y_axis.position, - y_axis.major_count, y_axis.num_ticks, y_axis.num_tick_labels, abs(tick_size), - tick_size > 0 ? 1 : -1, y_axis.label_position, axis); + auto tick_size = axis.tick_size; + // change sign of tick_size depending on the location of the colorbar + if (axis_elem->hasAttribute("tick_size")) + { + tick_size = static_cast(axis_elem->getAttribute("tick_size")); + if (location == "left" || location == "bottom") + { + tick_size *= -1.0; + axis_elem->setAttribute("tick_size", tick_size); + } + } + if (axis_elem->hasAttribute("_tick_size_set_by_user")) + { + tick_size = static_cast(axis_elem->getAttribute("_tick_size_set_by_user")); + if (static_cast(axis_elem->getAttribute("axis_type")) != axis_type) + { + tick_size *= -1.0; + axis_elem->setAttribute("_tick_size_set_by_user", tick_size); + } + } + + global_render->createAxis(axis.min, axis.max, axis.tick, axis.org, axis.position, axis.major_count, + axis.num_ticks, axis.num_tick_labels, abs(tick_size), tick_size > 0 ? 1 : -1, + axis.label_position, axis_elem); } } - if (axis != nullptr) + if (axis_elem != nullptr) { - axis->setAttribute("scale", 0); + axis_elem->setAttribute("scale", 0); if (del == del_values::update_without_default) { - axis->setAttribute("tick", c_tick); - axis->setAttribute("min_value", c_min); + axis_elem->setAttribute("tick", c_tick); + axis_elem->setAttribute("min_value", c_min); } } processFlip(element); - gr_freeaxis(&y_axis); + gr_freeaxis(&axis); } - if (axis != nullptr) + if (axis_elem != nullptr) { - axis->setAttribute("tick_size", PLOT_DEFAULT_COLORBAR_TICK_SIZE); + if (!axis_elem->hasAttribute("_tick_size_set_by_user")) + axis_elem->setAttribute("tick_size", (location == "left" || location == "bottom") + ? -PLOT_DEFAULT_COLORBAR_TICK_SIZE + : PLOT_DEFAULT_COLORBAR_TICK_SIZE); + else + axis_elem->setAttribute("tick_size", static_cast(axis_elem->getAttribute("_tick_size_set_by_user"))); + axis_elem->setAttribute("name", "colorbar " + axis_type + "-axis"); + axis_elem->setAttribute("axis_type", axis_type); if (del != del_values::update_without_default) { - axis->setAttribute("name", "colorbar y-axis"); - axis->setAttribute("axis_type", "y"); - axis->setAttribute("draw_grid", false); - axis->setAttribute("mirrored_axis", false); + axis_elem->setAttribute("draw_grid", false); + axis_elem->setAttribute("mirrored_axis", false); } } applyMoveTransformation(element); @@ -5643,12 +5748,12 @@ static void processBarplot(const std::shared_ptr &element, const s * \param[in] context The GRM::Context that contains the actual data */ - /* subplot level */ + /* plot level */ int bar_color = 989, edge_color = 1; std::vector bar_color_rgb = {-1, -1, -1}; std::vector edge_color_rgb = {-1, -1, -1}; double bar_width = 0.8, edge_width = 1.0, bar_shift = 1; - std::string style = "default", orientation = PLOT_DEFAULT_ORIENTATION; + std::string style = "default", orientation = PLOT_DEFAULT_ORIENTATION, line_spec = SERIES_DEFAULT_SPEC; double wfac; int len_std_colors = 20; int std_colors[20] = {989, 982, 980, 981, 996, 983, 995, 988, 986, 990, @@ -5675,12 +5780,18 @@ static void processBarplot(const std::shared_ptr &element, const s del = del_values(static_cast(element->getAttribute("_delete_children"))); clearOldChildren(&del, element); - /* retrieve attributes from the subplot level */ + /* retrieve attributes from the plot level */ auto plot_parent = element->parentElement(); getPlotParent(plot_parent); auto series_index = static_cast(element->getAttribute("series_index")); auto fixed_y_length = static_cast(plot_parent->getAttribute("max_y_length")); + // Todo: using line_spec here istn't really clean, cause no lines are drawn, but it's the only option atm to get the + // same different colors like multiple line series have + const char *spec_char = line_spec.c_str(); + gr_uselinespec((char *)spec_char); + gr_inqmarkercolorind(&bar_color); + if (element->hasAttribute("fill_color_rgb")) { auto bar_color_rgb_key = static_cast(element->getAttribute("fill_color_rgb")); @@ -5770,12 +5881,10 @@ static void processBarplot(const std::shared_ptr &element, const s ylabels_left = ylabels_length; } - if (element->hasAttribute("x_range_min") && element->hasAttribute("x_range_max") && - element->hasAttribute("y_range_min")) + if (element->hasAttribute("x_range_min") && element->hasAttribute("x_range_max")) { x_min = static_cast(element->getAttribute("x_range_min")); x_max = static_cast(element->getAttribute("x_range_max")); - y_min = static_cast(element->getAttribute("y_range_min")); if (!element->hasAttribute("bar_width")) { bar_width = (x_max - x_min) / (y_length - 1.0); @@ -5784,6 +5893,17 @@ static void processBarplot(const std::shared_ptr &element, const s wfac = 0.9 * bar_width; } } + if (style != "stacked" && element->hasAttribute("y_range_min")) + y_min = static_cast(element->getAttribute("y_range_min")); + auto coordinate_system = element->parentElement()->querySelectors("coordinate_system"); + if (coordinate_system != nullptr && coordinate_system->hasAttribute("y_line")) + { + auto y_line = coordinate_system->querySelectors("polyline[name=\"y_line\"]"); + if (y_line != nullptr) + { + y_min = static_cast(y_line->getAttribute(orientation == "horizontal" ? "y1" : "x1")); + } + } if (style != "lined" && inner_series) throw TypeError("Unsupported operation for barplot series.\n"); if (!c.empty()) @@ -5847,7 +5967,7 @@ static void processBarplot(const std::shared_ptr &element, const s } if (!inner_series) { - /* Draw Bar */ + /* draw bar */ for (i = 0; i < y_length; i++) { y1 = y_min; @@ -5899,10 +6019,7 @@ static void processBarplot(const std::shared_ptr &element, const s auto str = std::to_string(id); /* attributes for fill_rect */ - if (style != "default") - { - fillcolorind = std_colors[i % len_std_colors]; - } + if (style != "default") fillcolorind = std_colors[i % len_std_colors]; if (!c.empty() && c[i] != -1) { fillcolorind = c[i]; @@ -6011,10 +6128,7 @@ static void processBarplot(const std::shared_ptr &element, const s auto str = std::to_string(id); /* attributes for fill_rect */ - if (!c.empty() && !inner_c && c[inner_series_index] != -1) - { - fillcolorind = c[inner_series_index]; - } + if (!c.empty() && !inner_c && c[inner_series_index] != -1) fillcolorind = c[inner_series_index]; if (!c_rgb.empty() && !inner_c_rgb && c_rgb[inner_series_index * 3] != -1) { bar_fillcolor_rgb = @@ -6023,10 +6137,7 @@ static void processBarplot(const std::shared_ptr &element, const s bar_color_rgb_key = "fill_color_rgb" + str; (*context)[bar_color_rgb_key] = bar_fillcolor_rgb; } - if (inner_c && c[inner_y_start_index + i] != -1) - { - fillcolorind = c[inner_y_start_index + i]; - } + if (inner_c && c[inner_y_start_index + i] != -1) fillcolorind = c[inner_y_start_index + i]; if (inner_c_rgb && c_rgb[(inner_y_start_index + i) * 3] != -1) { bar_fillcolor_rgb = std::vector{c_rgb[(inner_y_start_index + i) * 3], @@ -6380,7 +6491,7 @@ static void processContourf(const std::shared_ptr &element, const static void processDrawArc(const std::shared_ptr &element, const std::shared_ptr &context) { /*! - * Processing function for drawArc + * Processing function for draw_arc * * \param[in] element The GRM::Element that contains the attributes and data keys * \param[in] context The GRM::Context that contains the actual data @@ -6392,7 +6503,10 @@ static void processDrawArc(const std::shared_ptr &element, const s auto start_angle = static_cast(element->getAttribute("start_angle")); auto end_angle = static_cast(element->getAttribute("end_angle")); applyMoveTransformation(element); + + if (static_cast(element->getAttribute("name")) == "rho-axes line") gr_setclip(0); if (redraw_ws) gr_drawarc(x_min, x_max, y_min, y_max, start_angle, end_angle); + if (static_cast(element->getAttribute("name")) == "rho-axes line") gr_setclip(1); } static void processDrawGraphics(const std::shared_ptr &element, @@ -6416,12 +6530,12 @@ static void processDrawGraphics(const std::shared_ptr &element, static void processDrawImage(const std::shared_ptr &element, const std::shared_ptr &context) { /*! - * Processing function for drawImage + * Processing function for draw_image * * \param[in] element The GRM::Element that contains the attributes and data keys * \param[in] context The GRM::Context that contains the actual data */ - int model; + int model = PLOT_DEFAULT_MODEL; auto x_min = static_cast(element->getAttribute("x_min")); auto x_max = static_cast(element->getAttribute("x_max")); auto y_min = static_cast(element->getAttribute("y_min")); @@ -6452,16 +6566,17 @@ static void processErrorBars(const std::shared_ptr &element, const double absolute_upwards_flt, relative_upwards_flt, absolute_downwards_flt, relative_downwards_flt; int scale_options, color_upwards_cap, color_downwards_cap, color_error_bar; double marker_size, x_min, x_max, y_min, y_max, tick, a, b, e_upwards, e_downwards, x_value; - double line_x[2], line_y[2]; + double line_x[2], line_y[2], last_line_y[2]; std::vector x_vec, y_vec; unsigned int x_length; std::string x_key, y_key; std::shared_ptr series; del_values del = del_values::update_without_default; int child_id = 0; + int error_bar_style = ERRORBAR_DEFAULT_STYLE; // line absolute_upwards_flt = absolute_downwards_flt = relative_upwards_flt = relative_downwards_flt = FLT_MAX; - if (static_cast(element->parentElement()->parentElement()->localName()) == "central_region") + if (element->parentElement()->parentElement()->localName() == "central_region") { series = element->parentElement(); } @@ -6478,7 +6593,7 @@ static void processErrorBars(const std::shared_ptr &element, const x_vec = GRM::get>((*context)[x_key]); y_vec = GRM::get>((*context)[y_key]); x_length = x_vec.size(); - kind = static_cast(series->parentElement()->getAttribute("kind")); + kind = static_cast(series->getAttribute("kind")); if (element->parentElement()->hasAttribute("orientation")) { orientation = static_cast(element->parentElement()->getAttribute("orientation")); @@ -6520,6 +6635,8 @@ static void processErrorBars(const std::shared_ptr &element, const relative_downwards_flt = static_cast(element->getAttribute("relative_downwards_flt")); if (element->hasAttribute("relative_upwards_flt")) relative_upwards_flt = static_cast(element->getAttribute("relative_upwards_flt")); + if (element->hasAttribute("error_bar_style")) + error_bar_style = static_cast(element->getAttribute("error_bar_style")); if (absolute_upwards_vec.empty() && relative_upwards_vec.empty() && absolute_upwards_flt == FLT_MAX && relative_upwards_flt == FLT_MAX && absolute_downwards_vec.empty() && relative_downwards_vec.empty() && @@ -6530,7 +6647,7 @@ static void processErrorBars(const std::shared_ptr &element, const is_horizontal = orientation == "horizontal"; - /* Getting GRM options and sizes. See gr_verrorbars. */ + /* Getting GRM options and sizes. See gr_verrorbars */ gr_savestate(); gr_inqmarkersize(&marker_size); gr_inqwindow(&x_min, &x_max, &y_min, &y_max); @@ -6558,7 +6675,6 @@ static void processErrorBars(const std::shared_ptr &element, const e_upwards = e_downwards = FLT_MAX; for (int i = 0; i < x_length; i++) { - std::shared_ptr error_bar; if (!absolute_upwards.empty() || !relative_upwards.empty() || absolute_upwards_flt != FLT_MAX || relative_upwards_flt != FLT_MAX) { @@ -6568,7 +6684,6 @@ static void processErrorBars(const std::shared_ptr &element, const (!absolute_upwards.empty() ? absolute_upwards_vec[i] : (absolute_upwards_flt != FLT_MAX ? absolute_upwards_flt : 0.)); } - if (!absolute_downwards.empty() || !relative_downwards.empty() || absolute_downwards_flt != FLT_MAX || relative_downwards_flt != FLT_MAX) { @@ -6580,62 +6695,121 @@ static void processErrorBars(const std::shared_ptr &element, const : (absolute_downwards_flt != FLT_MAX ? absolute_downwards_flt : 0.)); } - /* See gr_verrorbars for reference */ - x_value = x_vec[i]; - line_x[0] = X_LOG(X_LIN(x_value - tick, scale_options, x_min, x_max, a, b), scale_options, x_min, x_max, a, b); - line_x[1] = X_LOG(X_LIN(x_value + tick, scale_options, x_min, x_max, a, b), scale_options, x_min, x_max, a, b); - - if (!is_horizontal) + if (i > 0) { - double tmp1, tmp2; - tmp1 = line_x[0], tmp2 = line_x[1]; - line_x[0] = line_y[0], line_x[1] = line_y[1]; - line_y[0] = tmp1, line_y[1] = tmp2; + last_line_y[0] = line_y[0]; + last_line_y[1] = line_y[1]; } + line_y[0] = e_upwards != FLT_MAX ? e_upwards : y_vec[i]; + line_y[1] = e_downwards != FLT_MAX ? e_downwards : y_vec[i]; - if (color_error_bar >= 0) + if (error_bar_style == 0) { - line_y[0] = e_upwards != FLT_MAX ? e_upwards : y_vec[i]; - line_y[1] = e_downwards != FLT_MAX ? e_downwards : y_vec[i]; - if (del != del_values::update_without_default && del != del_values::update_with_default) - { - error_bar = global_render->createErrorBar(x_value, line_y[0], line_y[1], color_error_bar); - error_bar->setAttribute("_child_id", child_id++); - element->append(error_bar); - } - else + std::shared_ptr error_bar; + + /* See gr_verrorbars for reference */ + x_value = x_vec[i]; + line_x[0] = + X_LOG(X_LIN(x_value - tick, scale_options, x_min, x_max, a, b), scale_options, x_min, x_max, a, b); + line_x[1] = + X_LOG(X_LIN(x_value + tick, scale_options, x_min, x_max, a, b), scale_options, x_min, x_max, a, b); + + if (!is_horizontal) { - error_bar = element->querySelectors("error_bar[_child_id=" + std::to_string(child_id++) + "]"); - if (error_bar != nullptr) - global_render->createErrorBar(x_value, line_y[0], line_y[1], color_error_bar, error_bar); + double tmp1, tmp2; + tmp1 = line_x[0], tmp2 = line_x[1]; + line_x[0] = line_y[0], line_x[1] = line_y[1]; + line_y[0] = tmp1, line_y[1] = tmp2; } - if (error_bar != nullptr) + if (color_error_bar >= 0) { - if (e_upwards != FLT_MAX) + if (del != del_values::update_without_default && del != del_values::update_with_default) { - error_bar->setAttribute("e_upwards", e_upwards); - error_bar->setAttribute("upwards_cap_color", color_upwards_cap); + error_bar = global_render->createErrorBar(x_value, line_y[0], line_y[1], color_error_bar); + error_bar->setAttribute("_child_id", child_id++); + element->append(error_bar); } - if (e_downwards != FLT_MAX) + else { - error_bar->setAttribute("e_downwards", e_downwards); - error_bar->setAttribute("downwards_cap_color", color_downwards_cap); + error_bar = element->querySelectors("error_bar[_child_id=" + std::to_string(child_id++) + "]"); + if (error_bar != nullptr) + global_render->createErrorBar(x_value, line_y[0], line_y[1], color_error_bar, error_bar); } - if (e_downwards != FLT_MAX || e_upwards != FLT_MAX) + + if (error_bar != nullptr) { - error_bar->setAttribute("cap_x_min", line_x[0]); - error_bar->setAttribute("cap_x_max", line_x[1]); + if (e_upwards != FLT_MAX) + { + error_bar->setAttribute("e_upwards", e_upwards); + error_bar->setAttribute("upwards_cap_color", color_upwards_cap); + } + if (e_downwards != FLT_MAX) + { + error_bar->setAttribute("e_downwards", e_downwards); + error_bar->setAttribute("downwards_cap_color", color_downwards_cap); + } + if (e_downwards != FLT_MAX || e_upwards != FLT_MAX) + { + error_bar->setAttribute("cap_x_min", line_x[0]); + error_bar->setAttribute("cap_x_max", line_x[1]); + } } } } + else if (error_bar_style == 1 && color_error_bar >= 0) + { + std::vector f1, f2; + std::shared_ptr fill_area; + + if (i == 0) continue; + + // fill vector + f1.push_back(x_vec[i - 1]); + f2.push_back(last_line_y[0]); + f1.push_back(x_vec[i - 1]); + f2.push_back(last_line_y[1]); + f1.push_back(x_vec[i]); + f2.push_back(line_y[1]); + f1.push_back(x_vec[i]); + f2.push_back(line_y[0]); + + auto id = static_cast(global_root->getAttribute("_id")); + global_root->setAttribute("_id", id + 1); + auto str = std::to_string(id); + + if (del != del_values::update_without_default && del != del_values::update_with_default) + { + fill_area = global_render->createFillArea("x" + str, f1, "y" + str, f2, nullptr, 0, 0, color_error_bar); + fill_area->setAttribute("_child_id", child_id++); + element->append(fill_area); + } + else + { + fill_area = element->querySelectors("fill_area[_child_id=" + std::to_string(child_id++) + "]"); + if (fill_area != nullptr) + global_render->createFillArea("x" + str, f1, "y" + str, f2, nullptr, 0, 0, color_error_bar, fill_area); + } + if (fill_area != nullptr) + { + double transparency = 0.4; + int fill_int_style = 1; + + if (element->hasAttribute("transparency")) + transparency = static_cast(element->getAttribute("transparency")); + fill_area->setAttribute("transparency", transparency); + if (element->hasAttribute("fill_int_style")) + fill_int_style = static_cast(element->getAttribute("fill_int_style")); + fill_area->setAttribute("fill_int_style", fill_int_style); + } + } } gr_restorestate(); } static void processErrorBar(const std::shared_ptr &element, const std::shared_ptr &context) { - double cap_x_min, cap_x_max, e_upwards = FLT_MAX, e_downwards = FLT_MAX; + double cap_x_min = 0.0, cap_x_max = 0.0, e_upwards = FLT_MAX, e_downwards = FLT_MAX; double error_bar_x, error_bar_y_min, error_bar_y_max; int color_upwards_cap = 0, color_downwards_cap = 0, color_error_bar; std::shared_ptr line; @@ -6813,30 +6987,15 @@ static void processLegend(const std::shared_ptr &element, const st auto plot_parent = element->parentElement(); getPlotParent(plot_parent); - std::shared_ptr central_region, central_region_parent; - auto kind = static_cast(plot_parent->getAttribute("kind")); - - central_region_parent = plot_parent; - if (kind == "marginal_heatmap") central_region_parent = plot_parent->children()[0]; - for (const auto &child : central_region_parent->children()) - { - if (child->localName() == "central_region") - { - central_region = child; - break; - } - } + auto kind = static_cast(plot_parent->getAttribute("_kind")); render = std::dynamic_pointer_cast(element->ownerDocument()); - if (!render) - { - throw NotFoundError("No render-document found for element\n"); - } + if (!render) throw NotFoundError("No render-document found for element\n"); calculateViewport(element); applyMoveTransformation(element); - if (static_cast(plot_parent->getAttribute("kind")) != "pie") + if (kind != "pie") { double legend_symbol_x[2], legend_symbol_y[2]; int i, legend_elems = 0; @@ -6857,13 +7016,19 @@ static void processLegend(const std::shared_ptr &element, const st del = del_values(static_cast(element->getAttribute("_delete_children"))); /* get the amount of series which should be displayed inside the legend */ - for (const auto &series : element->parentElement()->children()) // central_region children + for (const auto &plot_child : element->parentElement()->children()) // central_region children { - if (series->localName() != "series_line" && series->localName() != "series_scatter") continue; - for (const auto &child : series->children()) + if (plot_child->localName() != "central_region") continue; + for (const auto &series : plot_child->children()) { - if (child->localName() != "polyline" && child->localName() != "polymarker") continue; - legend_elems += 1; + if (!str_equals_any(series->localName(), "series_line", "series_polar_line", "series_polar_scatter", + "series_scatter", "series_stairs", "series_stem")) + continue; + for (const auto &child : series->children()) + { + if (child->localName() != "polyline" && child->localName() != "polymarker") continue; + legend_elems += 1; + } } } if (element->hasAttribute("_legend_elems")) @@ -6889,38 +7054,42 @@ static void processLegend(const std::shared_ptr &element, const st render->setSelectSpecificXform(element, 0); render->setScale(element, 0); - if (del != del_values::update_without_default && del != del_values::update_with_default) - { - fr = render->createFillRect(viewport[0], viewport[1], viewport[3], viewport[2]); - fr->setAttribute("_child_id", child_id++); - element->append(fr); - } - else + if (legend_elems > 0) { - fr = element->querySelectors("fill_rect[_child_id=" + std::to_string(child_id++) + "]"); - if (fr != nullptr) render->createFillRect(viewport[0], viewport[1], viewport[3], viewport[2], 0, 0, -1, fr); - } + if (del != del_values::update_without_default && del != del_values::update_with_default) + { + fr = render->createFillRect(viewport[0], viewport[1], viewport[3], viewport[2]); + fr->setAttribute("_child_id", child_id++); + element->append(fr); + } + else + { + fr = element->querySelectors("fill_rect[_child_id=" + std::to_string(child_id++) + "]"); + if (fr != nullptr) + render->createFillRect(viewport[0], viewport[1], viewport[3], viewport[2], 0, 0, -1, fr); + } - render->setFillIntStyle(element, GKS_K_INTSTYLE_SOLID); - render->setFillColorInd(element, 0); + render->setFillIntStyle(element, GKS_K_INTSTYLE_SOLID); + render->setFillColorInd(element, 0); - if (del != del_values::update_without_default && del != del_values::update_with_default) - { - dr = render->createDrawRect(viewport[0], viewport[1], viewport[3], viewport[2]); - dr->setAttribute("_child_id", child_id++); - element->append(dr); - } - else - { - dr = element->querySelectors("draw_rect[_child_id=" + std::to_string(child_id++) + "]"); - if (dr != nullptr) render->createDrawRect(viewport[0], viewport[1], viewport[3], viewport[2], dr); - } + if (del != del_values::update_without_default && del != del_values::update_with_default) + { + dr = render->createDrawRect(viewport[0], viewport[1], viewport[3], viewport[2]); + dr->setAttribute("_child_id", child_id++); + element->append(dr); + } + else + { + dr = element->querySelectors("draw_rect[_child_id=" + std::to_string(child_id++) + "]"); + if (dr != nullptr) render->createDrawRect(viewport[0], viewport[1], viewport[3], viewport[2], dr); + } - if (dr != nullptr && del != del_values::update_without_default) - { - render->setLineType(dr, GKS_K_INTSTYLE_SOLID); - render->setLineColorInd(dr, 1); - render->setLineWidth(dr, 1); + if (dr != nullptr && del != del_values::update_without_default) + { + render->setLineType(dr, GKS_K_INTSTYLE_SOLID); + render->setLineColorInd(dr, 1); + render->setLineWidth(dr, 1); + } } i = 0; @@ -6934,15 +7103,24 @@ static void processLegend(const std::shared_ptr &element, const st { int mask; double dy; + bool got_polyline = false, got_polymarker = false; - if (series->localName() != "series_line" && series->localName() != "series_scatter") continue; + if (!str_equals_any(series->localName(), "series_line", "series_polar_line", "series_polar_scatter", + "series_scatter", "series_stairs", "series_stem")) + continue; - if (i <= labels.size()) + if (i < labels.size()) { gr_inqtext(0, 0, labels[i].data(), tbx, tby); dy = grm_max((tby[2] - tby[0]) - 0.03 * scale_factor, 0); viewport[3] -= 0.5 * dy; } + else + { + // if there are less label than elements the calculation above won't work -> only include elemts to + // the legend which also have a label + continue; + } gr_savestate(); mask = gr_uselinespec(specs[spec_i].data()); @@ -6957,6 +7135,12 @@ static void processLegend(const std::shared_ptr &element, const st for (const auto &child : series->children()) { std::shared_ptr pl; + if (series->localName() == "series_stem") + { + if (got_polymarker && got_polyline) break; + if (child->localName() == "polyline" && got_polyline) continue; + if (child->localName() == "polymarker" && got_polymarker) continue; + } if (child->localName() == "polyline") { if (del != del_values::update_without_default && del != del_values::update_with_default) @@ -6984,6 +7168,7 @@ static void processLegend(const std::shared_ptr &element, const st { render->setLineColorInd(pl, static_cast(series->getAttribute("line_color_ind"))); } + got_polyline = true; } } else if (child->localName() == "polymarker") @@ -7013,11 +7198,15 @@ static void processLegend(const std::shared_ptr &element, const st } if (pl != nullptr) { - render->setMarkerColorInd( - pl, (series->hasAttribute("marker_color_ind") - ? static_cast(series->getAttribute("marker_color_ind")) - : 989)); + int marker_color_ind = 989; + if (series->hasAttribute("marker_color_ind")) + marker_color_ind = static_cast(series->getAttribute("marker_color_ind")); + if (child->hasAttribute("marker_color_ind")) + marker_color_ind = static_cast(child->getAttribute("marker_color_ind")); + render->setMarkerColorInd(pl, marker_color_ind); + if (series->localName() == "series_stem") pl->setAttribute("x", legend_symbol_x[1]); processMarkerColorInd(pl); + got_polymarker = true; } } } @@ -7102,7 +7291,7 @@ static void processLegend(const std::shared_ptr &element, const st if (del != del_values::update_without_default && del != del_values::update_with_default) { tx = render->createText(viewport[0] + 0.08 * scale_factor, viewport[3] - 0.03 * scale_factor, - labels[i].data()); + labels[i]); tx->setAttribute("_child_id", child_id++); element->append(tx); } @@ -7111,7 +7300,7 @@ static void processLegend(const std::shared_ptr &element, const st tx = element->querySelectors("text[_child_id=" + std::to_string(child_id++) + "]"); if (tx != nullptr) render->createText(viewport[0] + 0.08 * scale_factor, viewport[3] - 0.03 * scale_factor, - labels[i].data(), CoordinateSpace::NDC, tx); + labels[i], CoordinateSpace::NDC, tx); } if (tx != nullptr && del != del_values::update_without_default) { @@ -7294,221 +7483,880 @@ static void processLegend(const std::shared_ptr &element, const st processFillColorInd(element); } -static void processPolarAxes(const std::shared_ptr &element, const std::shared_ptr &context) +static void calculatePolarLimits(const std::shared_ptr ¢ral_region, + const std::shared_ptr &context) { - double viewport[4]; - double r_min, r_max; - double tick; - double x[2], y[2]; - int i, n; - double alpha; - char text_buffer[PLOT_POLAR_AXES_TEXT_BUFFER]; + double r_min = 0.0, r_max = 0.0, tick; + double min_scale = 0, max_scale; // used for y_log (with negative exponents) + int rings = -1; std::string kind; - int angle_ticks, rings; - bool phiflip = false; - double interval; - std::string title, norm; - del_values del = del_values::update_without_default; - int child_id = 0; - std::shared_ptr render; - std::shared_ptr central_region; + double y_lim_min = 0.0, y_lim_max = 0.0; + bool y_lims = false, y_log = false, keep_radii_axes = false; + std::shared_ptr plot_parent = central_region; + getPlotParent(plot_parent); - render = std::dynamic_pointer_cast(element->ownerDocument()); - if (!render) + if (plot_parent->hasAttribute("y_log")) y_log = static_cast(plot_parent->getAttribute("y_log")); + kind = static_cast(plot_parent->getAttribute("_kind")); + + if (central_region->hasAttribute("r_min")) + r_min = (kind == "uniform_polar_heatmap") ? 0.0 : static_cast(central_region->getAttribute("r_min")); + if (central_region->hasAttribute("r_max")) r_max = static_cast(central_region->getAttribute("r_max")); + + if (plot_parent->hasAttribute("y_lim_min") && plot_parent->hasAttribute("y_lim_max")) { - throw NotFoundError("No render-document for element found\n"); + y_lims = true; + y_lim_min = static_cast(plot_parent->getAttribute("y_lim_min")); + y_lim_max = static_cast(plot_parent->getAttribute("y_lim_max")); } - auto subplotElement = getSubplotElement(element); - for (const auto &child : subplotElement->children()) // no special case for marginal_heatmap cause the plot is polar + if (y_log && y_lim_min == 0.0) { - if (child->localName() == "central_region") - { - central_region = child; - break; - } + y_lim_min = pow(10, -1); + plot_parent->setAttribute("y_lim_min", y_lim_min); } - viewport[0] = static_cast(central_region->getAttribute("viewport_x_min")); - viewport[1] = static_cast(central_region->getAttribute("viewport_x_max")); - viewport[2] = static_cast(central_region->getAttribute("viewport_y_min")); - viewport[3] = static_cast(central_region->getAttribute("viewport_y_max")); - - r_min = static_cast(subplotElement->getAttribute("_y_lim_min")); - r_max = static_cast(subplotElement->getAttribute("_y_lim_max")); - - angle_ticks = static_cast(element->getAttribute("angle_ticks")); - - kind = static_cast(subplotElement->getAttribute("kind")); + if (plot_parent->hasAttribute("keep_radii_axes")) + keep_radii_axes = static_cast(plot_parent->getAttribute("keep_radii_axes")); - render->setLineType(element, GKS_K_LINETYPE_SOLID); - - if (kind == "polar_histogram") + if ((kind == "polar_histogram" && (!y_lims || keep_radii_axes)) || + ((kind == "polar_line" || kind == "polar_scatter") && !y_lims)) { - auto max = static_cast(central_region->getAttribute("r_max")); - - // check if rings are given - rings = -1; - norm = static_cast(element->getAttribute("norm")); + if (kind == "polar_histogram" || ((kind == "polar_line" || kind == "polar_scatter") && !y_log)) + { + if (kind == "polar_line" || kind == "polar_scatter") + { + // find the maximum yrange of all series, so that all plots are visible + for (const auto &series_elem : central_region->querySelectorsAll("series_" + kind)) + { + r_max = grm_max(r_max, static_cast(series_elem->getAttribute("y_range_max"))); + } + } + r_min = 0.0; + if (kind == "polar_histogram" && y_log) r_min = 1.0; + tick = autoTick(r_min, r_max); + rings = (int)round(r_max / tick); + if (rings * tick < r_max) rings += 1; + } + else if ((kind == "polar_line" || kind == "polar_scatter") && y_log) + { + if (r_max <= 0.0) throw InvalidValueError("The max radius has to be bigger than 0.0 when using y_log"); + max_scale = ceil(log10(r_max)); - tick = autoTickRingsPolar(max, rings, norm); - central_region->setAttribute("tick", tick); - max = tick * rings; + if (r_min > 0.0) + { + min_scale = ceil(abs(log10(r_min))); + if (min_scale != 0.0) min_scale *= (log10(r_min) / abs(log10(r_min))); + } + else + { + min_scale = 0.0; + if (max_scale <= 0) min_scale = max_scale - 5; + } - central_region->setAttribute("r_max", max); - central_region->setAttribute("rings", rings); + if (max_scale == min_scale) + { + throw InvalidValueError( + "The minimum and maximum radius are of the same magnitude, incompatible with the y_log option"); + } - r_min = 0.0; + // Todo: smart ring calculation for y_log especially with large differences in magnitudes (other cases + // too) + r_min = pow(10, min_scale); + rings = int(abs(abs(max_scale) - abs(min_scale))); + // overwrite r_max and r_min because of rounded scales? + central_region->setAttribute("r_max", pow(10, max_scale)); + } + if ((kind != "polar_line" && kind != "polar_scatter") || !y_log) + { + central_region->setAttribute("tick", tick); + central_region->setAttribute("r_max", tick * rings); + } + central_region->setAttribute("r_min", r_min); } else { - rings = grm_max(4, (int)(r_max - r_min)); - element->setAttribute("rings", rings); + // currently only plot_polar y_log is supported + if ((kind == "polar_line" || kind == "polar_scatter") && y_log) // also with y_lims + { + max_scale = ceil(abs(log10(y_lim_max))); + if (max_scale != 0.0) max_scale *= log10(y_lim_max) / abs(log10(y_lim_max)); + + if (y_lim_min <= 0.0) + { + min_scale = (max_scale <= 0) ? max_scale - 5 : 0; + if (r_min > 0.0) min_scale = ceil(abs(log10(r_min))) * (log10(r_min) / abs(log10(r_min))); + y_lim_min = pow(10, min_scale); + plot_parent->setAttribute("y_lim_min", y_lim_min); + } + else + { + min_scale = ceil(abs(log10(y_lim_min))); + if (min_scale != 0.0) min_scale *= (log10(y_lim_min) / abs(log10(y_lim_min))); + } - if (element->hasAttribute("tick")) + rings = grm_min(static_cast(max_scale - min_scale), 12); // number of rings should not exceed 12? + central_region->setAttribute("r_min", pow(10, min_scale)); + central_region->setAttribute("r_max", pow(10, max_scale)); + } + else // this currently includes polar(y_lims), p_hist(y_lims, !keep_radii_axes), polar_heatmap(all cases) { - tick = static_cast(element->getAttribute("tick")); + if (y_lims) + { + r_max = y_lim_max; + central_region->setAttribute("r_min", y_lim_min); + } + else if (central_region->hasAttribute("tick")) + { + rings = grm_max(4, (int)(r_max - r_min)); + tick = static_cast(central_region->getAttribute("tick")); + r_max = tick * rings; + central_region->setAttribute("r_min", r_min); + } + else // nothing given + { + tick = autoTick(r_min, r_max); + } + central_region->setAttribute("r_max", r_max); } - else + } +} + +static void adjustPolarGridLineTextPosition(double x_lim_min, double x_lim_max, double *x_r, double *y_r, double value, + std::shared_ptr central_region) +{ + double window[4]; + double x0, y0; + + window[0] = static_cast(central_region->getAttribute("window_x_min")); + window[1] = static_cast(central_region->getAttribute("window_x_max")); + window[2] = static_cast(central_region->getAttribute("window_y_min")); + window[3] = static_cast(central_region->getAttribute("window_y_max")); + if (x_lim_min > 0 || x_lim_max < 360) + { + // calculate unscaled position for label + x0 = std::cos(x_lim_min * M_PI / 180.0), y0 = std::sin(x_lim_min * M_PI / 180.0); + // scale label with the real value of the arc + x0 *= value * window[3]; + y0 *= value * window[3]; + // add small offset to the resulting position so that the label have some space to the polyline + // tested by going through the angles by steps of 15 degree + if (x_lim_min <= 135 && x_lim_min >= 45) + x0 += 0.03 * (window[1] - window[0]) / 2.0; + else if (x_lim_min >= 225 && x_lim_min <= 315) + x0 -= 0.03 * (window[1] - window[0]) / 2.0; + if (x_lim_min < 23 && x_lim_min >= 0) + y0 -= 0.03 * (window[3] - window[2]) / 2.0; + else if (x_lim_min < 45 && x_lim_min >= 23) + y0 -= 0.015 * (window[3] - window[2]) / 2.0; + else if (x_lim_min > 45 && x_lim_min <= 68) + y0 += 0.015 * (window[3] - window[2]) / 2.0; + else if (x_lim_min > 68 && x_lim_min < 90) + y0 += 0.03 * (window[3] - window[2]) / 2.0; + else if (x_lim_min < 112 && x_lim_min > 90) + y0 -= 0.03 * (window[3] - window[2]) / 2.0; + else if (x_lim_min >= 112 && x_lim_min < 135) + y0 -= 0.015 * (window[3] - window[2]) / 2.0; + else if (x_lim_min > 135 && x_lim_min <= 158) + y0 += 0.015 * (window[3] - window[2]) / 2.0; + else if (x_lim_min < 180 && x_lim_min > 158) + y0 += 0.03 * (window[3] - window[2]) / 2.0; + else if (x_lim_min < 180 && x_lim_min > 135) + y0 += 0.03 * (window[3] - window[2]) / 2.0; + else if (x_lim_min < 180 && x_lim_min > 135) + y0 += 0.03 * (window[3] - window[2]) / 2.0; + else if (x_lim_min >= 202 && x_lim_min < 225) + y0 += 0.015 * (window[3] - window[2]) / 2.0; + else if (x_lim_min <= 248 && x_lim_min > 225) + y0 -= 0.015 * (window[3] - window[2]) / 2.0; + else if (x_lim_min < 270 && x_lim_min > 248) + y0 -= 0.03 * (window[3] - window[2]) / 2.0; + else if (x_lim_min > 270 && x_lim_min < 292) + y0 += 0.03 * (window[3] - window[2]) / 2.0; + else if (x_lim_min >= 292 && x_lim_min < 315) + y0 += 0.015 * (window[3] - window[2]) / 2.0; + else if (x_lim_min > 315 && x_lim_min <= 338) + y0 -= 0.015 * (window[3] - window[2]) / 2.0; + else if (x_lim_min > 338) + y0 -= 0.03 * (window[3] - window[2]) / 2.0; + *x_r = x0; + *y_r = y0; + } +} + +static void processArcGridLine(const std::shared_ptr &element, + const std::shared_ptr &context) +{ + double window[4]; + std::string kind, arc_label; + del_values del = del_values::update_without_default; + int child_id = 0; + bool y_log = false, with_pan = false; + double x_lim_min = 0, x_lim_max = 360; + std::shared_ptr text, arc, plot_parent = element, central_region; + + getPlotParent(plot_parent); + for (const auto &child : plot_parent->children()) + { + if (child->localName() == "central_region") { - tick = autoTick(r_min, r_max); + central_region = child; + break; } } - /* clear old polar_axes_elements */ + with_pan = + plot_parent->hasAttribute("polar_with_pan") && static_cast(plot_parent->getAttribute("polar_with_pan")); + + /* clear old arc_grid_lines */ del = del_values(static_cast(element->getAttribute("_delete_children"))); clearOldChildren(&del, element); - n = rings; - phiflip = static_cast(subplotElement->getAttribute("phi_flip")); + window[0] = static_cast(central_region->getAttribute("window_x_min")); + window[1] = static_cast(central_region->getAttribute("window_x_max")); + window[2] = static_cast(central_region->getAttribute("window_y_min")); + window[3] = static_cast(central_region->getAttribute("window_y_max")); + + global_render->setLineType(element, GKS_K_LINETYPE_SOLID); + global_render->setTextAlign(element, GKS_K_TEXT_HALIGN_LEFT, GKS_K_TEXT_VALIGN_HALF); - // Draw rings - for (i = 0; i <= n; i++) + kind = static_cast(plot_parent->getAttribute("_kind")); + if (plot_parent->hasAttribute("y_log")) y_log = static_cast(plot_parent->getAttribute("y_log")); + if (plot_parent->hasAttribute("x_lim_min") && plot_parent->hasAttribute("x_lim_max")) { - std::shared_ptr arc; - double r = 1.0 / n * i; - if (del != del_values::update_without_default && del != del_values::update_with_default) + x_lim_min = static_cast(plot_parent->getAttribute("x_lim_min")); + x_lim_max = static_cast(plot_parent->getAttribute("x_lim_max")); + } + if (with_pan) + { + x_lim_min = 0; + x_lim_max = 360; + } + + auto value = static_cast(element->getAttribute("value")); + if (element->hasAttribute("arc_label")) arc_label = static_cast(element->getAttribute("arc_label")); + + if (del != del_values::update_without_default && del != del_values::update_with_default) + { + if (!with_pan) + arc = global_render->createDrawArc(value * window[0], value * window[1], value * window[2], value * window[3], + x_lim_min, x_lim_max); + else + arc = global_render->createDrawArc(-value, value, -value, value, x_lim_min, x_lim_max); + arc->setAttribute("_child_id", child_id++); + element->append(arc); + } + else + { + arc = element->querySelectors("draw_arc[_child_id=" + std::to_string(child_id++) + "]"); + if (!with_pan && arc != nullptr) + global_render->createDrawArc(value * window[0], value * window[1], value * window[2], value * window[3], + x_lim_min, x_lim_max, arc); + else if (arc != nullptr) + global_render->createDrawArc(-value, value, -value, value, x_lim_min, x_lim_max, arc); + } + if (arc != nullptr) + { + if (kind != "polar_heatmap" && kind != "nonuniform_polar_heatmap") arc->setAttribute("z_index", -1); + arc->setAttribute("name", "polar grid line"); + if (element->hasAttribute("line_color_ind")) + arc->setAttribute("line_color_ind", static_cast(element->getAttribute("line_color_ind"))); + } + + if (!arc_label.empty()) + { + double x0 = 0.05, y0 = value; + if (!with_pan) { - arc = render->createDrawArc(-r, r, -r, r, 0, 360); - arc->setAttribute("_child_id", child_id++); - element->append(arc); + x0 *= ((window[1] - window[0]) / 2.0); + y0 *= window[3]; + } + + adjustPolarGridLineTextPosition(x_lim_min, x_lim_max, &x0, &y0, value, central_region); + + if (with_pan) text = element->querySelectors("text[_child_id=" + std::to_string(child_id) + "]"); + if ((del != del_values::update_without_default && del != del_values::update_with_default) || + (with_pan && text == nullptr)) + { + text = global_render->createText(x0, y0, arc_label, CoordinateSpace::WC); + text->setAttribute("_child_id", child_id++); + element->append(text); } else { - arc = element->querySelectors("draw_arc[_child_id=" + std::to_string(child_id++) + "]"); - if (arc != nullptr) render->createDrawArc(-r, r, -r, r, 0, 360, arc); + text = element->querySelectors("text[_child_id=" + std::to_string(child_id++) + "]"); + if (text != nullptr) global_render->createText(x0, y0, arc_label, CoordinateSpace::WC, text); } - if (arc != nullptr) arc->setAttribute("name", "polar_axes"); - if (i % 2 == 0) + if (text != nullptr) { - if (i > 0) + if (y_log) text->setAttribute("scientific_format", 2); + if (element->parentElement()->hasAttribute("scientific_format")) + { + auto scientific_format = static_cast(element->parentElement()->getAttribute("scientific_format")); + text->setAttribute("scientific_format", scientific_format); + } + text->setAttribute("z_index", 1); + if (x_lim_min > 0 || x_lim_max < 360) { - if (arc != nullptr && del != del_values::update_without_default) render->setLineColorInd(arc, 88); + // use correct aligment for non standard axes + if (x_lim_min == 180 || x_lim_min == 0) + text->setAttribute("text_align_horizontal", "center"); + else if (x_lim_min < 180) + text->setAttribute("text_align_horizontal", "left"); + else if (x_lim_min > 180) + text->setAttribute("text_align_horizontal", "right"); + if (x_lim_min < 90 || x_lim_min > 270) + text->setAttribute("text_align_vertical", "top"); + else if (x_lim_min == 90 || x_lim_min == 270) + text->setAttribute("text_align_vertical", "half"); + else if (x_lim_min > 90 && x_lim_min < 270) + text->setAttribute("text_align_vertical", "bottom"); } } - else + } + else if (with_pan) + { + text = element->querySelectors("text[_child_id=" + std::to_string(child_id++) + "]"); + if (text != nullptr) element->removeChild(text); + } +} + +static void processRhoAxes(const std::shared_ptr &element, const std::shared_ptr &context) +{ + double window[4], old_window[4]; + double first_tick, last_tick, new_tick, r_max; + double min_scale = 0, max_scale; // used for y_log (with negative exponents) + double factor = 1; + int i, start_n = 1, labeled_arc_line_skip; + std::string kind; + del_values del = del_values::update_without_default; + int child_id = 0; + double y_lim_min = NAN, y_lim_max = NAN; + bool y_log = false, skip_calculations = false, keep_radii_axes = false, with_pan = false; + std::shared_ptr central_region, plot_parent = element; + int scientific_format = 0; + + getPlotParent(plot_parent); + for (const auto &child : plot_parent->children()) + { + if (child->localName() == "central_region") { - if (arc != nullptr && del != del_values::update_without_default) render->setLineColorInd(arc, 90); + central_region = child; + break; } } - // Draw sectorlines - interval = 360.0 / angle_ticks; - for (alpha = 0.0; alpha < 360; alpha += interval) + window[0] = static_cast(central_region->getAttribute("window_x_min")); + window[1] = static_cast(central_region->getAttribute("window_x_max")); + window[2] = static_cast(central_region->getAttribute("window_y_min")); + window[3] = static_cast(central_region->getAttribute("window_y_max")); + + with_pan = + plot_parent->hasAttribute("polar_with_pan") && static_cast(plot_parent->getAttribute("polar_with_pan")); + if (with_pan) + { + factor = grm_max(abs(window[0]), grm_max(abs(window[1]), grm_max(abs(window[2]), abs(window[3])))) * sqrt(2); + if (element->hasAttribute("_window_old_x_min")) + old_window[0] = static_cast(element->getAttribute("_window_old_x_min")); + if (element->hasAttribute("_window_old_x_max")) + old_window[1] = static_cast(element->getAttribute("_window_old_x_max")); + if (element->hasAttribute("_window_old_y_min")) + old_window[2] = static_cast(element->getAttribute("_window_old_y_min")); + if (element->hasAttribute("_window_old_y_max")) + old_window[3] = static_cast(element->getAttribute("_window_old_y_max")); + element->setAttribute("_window_old_x_min", window[0]); + element->setAttribute("_window_old_x_max", window[1]); + element->setAttribute("_window_old_y_min", window[2]); + element->setAttribute("_window_old_y_max", window[3]); + if (old_window[0] == window[0] && old_window[1] == window[1] && old_window[2] == window[2] && + old_window[3] == window[3]) + return; + } + + if (element->hasAttribute("scientific_format")) + scientific_format = static_cast(element->getAttribute("scientific_format")); + + if (plot_parent->hasAttribute("y_lim_min") && plot_parent->hasAttribute("y_lim_max")) { - std::shared_ptr line, text; - x[0] = std::cos(alpha * M_PI / 180.0); - y[0] = std::sin(alpha * M_PI / 180.0); - x[1] = 0.0; - y[1] = 0.0; + y_lim_min = static_cast(plot_parent->getAttribute("y_lim_min")); + y_lim_max = static_cast(plot_parent->getAttribute("y_lim_max")); + if (plot_parent->hasAttribute("keep_radii_axes")) + keep_radii_axes = static_cast(plot_parent->getAttribute("keep_radii_axes")); + } - if (del != del_values::update_without_default && del != del_values::update_with_default) + if (central_region->hasAttribute("_skip_calculations")) + { + skip_calculations = static_cast(central_region->getAttribute("_skip_calculations")); + central_region->removeAttribute("_skip_calculations"); + } + + if (!skip_calculations) calculatePolarLimits(central_region, context); + + kind = static_cast(plot_parent->getAttribute("_kind")); + if (plot_parent->hasAttribute("y_log")) y_log = static_cast(plot_parent->getAttribute("y_log")); + + global_render->setLineType(element, GKS_K_LINETYPE_SOLID); + + /* clear old rho_axes_elements */ + del = del_values(static_cast(element->getAttribute("_delete_children"))); + clearOldChildren(&del, element); + + // Draw Text + global_render->setTextAlign(element, GKS_K_TEXT_HALIGN_LEFT, GKS_K_TEXT_VALIGN_HALF); + + if (!grm_isnan(y_lim_min) && !grm_isnan(y_lim_max) && !keep_radii_axes) + { + first_tick = y_lim_min; + last_tick = y_lim_max; + } + else + { + // without y_lim_min and y_lim_max the origin/first_tick is always 0.0 except for y_log + last_tick = static_cast(central_region->getAttribute("r_max")); + first_tick = (y_log) ? static_cast(central_region->getAttribute("r_min")) : 0.0; + } + + if (y_log) // min_scale only needed with y_log + { + min_scale = ceil(abs(log10(first_tick))); + if (min_scale != 0.0) min_scale *= (log10(first_tick) / abs(log10(first_tick))); + + max_scale = ceil(abs(log10(last_tick))); + if (max_scale != 0.0) max_scale *= log10(last_tick) / abs(log10(last_tick)); // add signum of max_scale if not 0.0 + } + + // for currently unsupported y_log polar plots (hist, heatmap) + if (std::isnan(min_scale)) y_log = false; + + r_max = last_tick; + if (element->hasAttribute("_r_max")) r_max = static_cast(element->getAttribute("_r_max")); + if ((central_region->hasAttribute("_zoomed") && static_cast(central_region->getAttribute("_zoomed"))) || + r_max != last_tick) + { + for (const auto &child : element->children()) { - line = render->createPolyline(x[0], x[1], y[0], y[1]); - line->setAttribute("_child_id", child_id++); - element->append(line); + // Todo: Change this + child->remove(); + } + del = del_values::recreate_own_children; + } + new_tick = autoTick(first_tick, r_max); + + auto n = (int)round(((r_max * factor) - first_tick) / new_tick); + if (n <= 4 && kind != "polar_histogram") // special case to get some more useful axes + { + new_tick /= 2; + n *= 2; + } + + if (y_log) + { + start_n = 2 * floor(log10(last_tick) - log10(first_tick)) * factor; + n = 2 * floor(log10(r_max) - log10(first_tick)) * factor; + } + // mechanism to reduce the labels for polar_with_pan and y_log, where n could be pretty high + labeled_arc_line_skip = 2 + 2 * floor(n / 15); + + int cnt = labeled_arc_line_skip; + for (i = 0; i <= n + 1; i++) // Create arc_grid_lines and rho_axes line + { + std::shared_ptr arc_grid_line; + std::string value_string; + char text_buffer[PLOT_POLAR_AXES_TEXT_BUFFER] = ""; + double r; + if (!y_log) + { + r = i * new_tick / (r_max - first_tick); } else { - line = element->querySelectors("polyline[_child_id=" + std::to_string(child_id++) + "]"); - if (line != nullptr) render->createPolyline(x[0], x[1], y[0], y[1], 0, 0.0, 0, line); + r = ((i / 2) + (i % 2 == 1 ? log10(5) : 0)) / (log10(r_max) - log10(first_tick)); + if (!with_pan && r > 1) r = 1; } - if (line != nullptr && del != del_values::update_without_default) render->setLineColorInd(line, 88); - if (line != nullptr) line->setAttribute("name", "polar_axes"); - x[0] *= 1.1; - y[0] *= 1.1; - if (!phiflip) + if (i == n + 1) r = 1; + if (!with_pan && r > 1) continue; + if (i % labeled_arc_line_skip == 0 || r == 1) { - snprintf(text_buffer, PLOT_POLAR_AXES_TEXT_BUFFER, "%d\xc2\xb0", (int)grm_round(alpha)); + double value = first_tick + i * new_tick; + if (y_log) value = pow(10, (i / 2) + floor(log10(first_tick))); + if (r == 1) + { + double tmp_tick = (last_tick - first_tick) / n; + if (!with_pan) tmp_tick *= (abs(window[3] - window[2]) / 2.0); + + if (y_log && !with_pan) + value = + first_tick + pow(10, floor(log10(first_tick)) + start_n / 2 * (abs(window[3] - window[2]) / 2.0)); + else + value = (i == n + 1) ? first_tick + tmp_tick * (i - ((i - 1) * tmp_tick / (r_max - first_tick))) + : first_tick + tmp_tick * i; + element->setAttribute("_r_max", value); + } + if (!with_pan || (r > window[2] && window[3] > r)) + { + if (y_log) // y_log uses the exponential notation + { + snprintf(text_buffer, PLOT_POLAR_AXES_TEXT_BUFFER, "%d^{%.0f}", 10, log10(value)); + value_string = text_buffer; + } + else + { + format_reference_t reference; + gr_getformat(&reference, first_tick, first_tick, last_tick, new_tick, 2); + snprintf(text_buffer, PLOT_POLAR_AXES_TEXT_BUFFER, "%s", std::to_string(value).c_str()); + value_string = gr_ftoa(text_buffer, value, &reference); + + if (value_string.size() > 7) + { + reference = {1, 1}; + const char minus[] = {(char)0xe2, (char)0x88, (char)0x92, '\0'}; // gr minus sign + auto em_dash = std::string(minus); + size_t start_pos = 0; + + scientific_format = 2; + gr_setscientificformat(scientific_format); + + if (starts_with(value_string, em_dash)) start_pos = em_dash.size(); + auto without_minus = value_string.substr(start_pos); + + snprintf(text_buffer, PLOT_POLAR_AXES_TEXT_BUFFER, "%s", without_minus.c_str()); + value_string = gr_ftoa(text_buffer, atof(without_minus.c_str()), &reference); + if (start_pos != 0) value_string = em_dash.append(value_string); + element->setAttribute("scientific_format", scientific_format); + } + } + } + } + + // skip the lines without label in y_log case + if (i > cnt) cnt += labeled_arc_line_skip; + if (y_log && i != cnt && (labeled_arc_line_skip != 2 || i != cnt - 1) && (r != 1 && !with_pan)) continue; + + if (r != 1) + { + if (del != del_values::update_without_default && del != del_values::update_with_default) + { + arc_grid_line = global_render->createArcGridLine(r); + arc_grid_line->setAttribute("_child_id", child_id++); + element->append(arc_grid_line); + } + else + { + arc_grid_line = element->querySelectors("arc_grid_line[_child_id=" + std::to_string(child_id++) + "]"); + if (arc_grid_line != nullptr) global_render->createArcGridLine(r, arc_grid_line); + } + if (arc_grid_line != nullptr) + { + int line_color_ind = 90; // Todo: make the line_color editable like 2d axis + if (i % 2 == 0 && i > 0) line_color_ind = 88; + arc_grid_line->setAttribute("line_color_ind", line_color_ind); + if (!value_string.empty()) arc_grid_line->setAttribute("arc_label", value_string); + } } else { - if (alpha == 0.0) - snprintf(text_buffer, PLOT_POLAR_AXES_TEXT_BUFFER, "%d\xc2\xb0", 0); + std::shared_ptr arc, text; + double x_lim_min = 0, x_lim_max = 360; + if (plot_parent->hasAttribute("x_lim_min") && plot_parent->hasAttribute("x_lim_max")) + { + x_lim_min = static_cast(plot_parent->getAttribute("x_lim_min")); + x_lim_max = static_cast(plot_parent->getAttribute("x_lim_max")); + } + double x0 = 0.05 * (window[1] - window[0]) / 2.0; + + if (del != del_values::update_without_default && del != del_values::update_with_default) + { + if (!with_pan) + arc = global_render->createDrawArc(window[0], window[1], window[2], window[3], x_lim_min, x_lim_max); + else + arc = global_render->createDrawArc(-1, 1, -1, 1, x_lim_min, x_lim_max); + arc->setAttribute("_child_id", child_id++); + element->append(arc); + } else - snprintf(text_buffer, PLOT_POLAR_AXES_TEXT_BUFFER, "%d\xc2\xb0", 330 - (int)grm_round(alpha - interval)); + { + arc = element->querySelectors("draw_arc[_child_id=" + std::to_string(child_id++) + "]"); + if (arc != nullptr && !with_pan) + global_render->createDrawArc(window[0], window[1], window[2], window[3], x_lim_min, x_lim_max, arc); + else if (arc != nullptr) + global_render->createDrawArc(-1, 1, -1, 1, x_lim_min, x_lim_max, arc); + } + if (arc != nullptr) + { + if (!with_pan) arc->setAttribute("name", "rho-axes line"); + arc->setAttribute("line_color_ind", 88); + } + + if (i % labeled_arc_line_skip == 0 && i == n) + { + double y0 = window[3]; + + adjustPolarGridLineTextPosition(x_lim_min, x_lim_max, &x0, &y0, 1, central_region); + if (del != del_values::update_without_default && del != del_values::update_with_default) + { + text = global_render->createText(x0, y0, value_string, CoordinateSpace::WC); + text->setAttribute("_child_id", child_id++); + element->append(text); + } + else + { + text = element->querySelectors("text[_child_id=" + std::to_string(child_id++) + "]"); + if (text != nullptr) global_render->createText(x0, y0, value_string, CoordinateSpace::WC, text); + } + if (text != nullptr) + { + text->setAttribute("name", "rho-axes line"); + if (y_log) text->setAttribute("scientific_format", 2); + if (element->hasAttribute("scientific_format")) + text->setAttribute("scientific_format", scientific_format); + if (x_lim_min > 0 || x_lim_max < 360) + { + // use correct aligment for non standard axes + if (x_lim_min == 180 || x_lim_min == 0) + text->setAttribute("text_align_horizontal", "center"); + else if (x_lim_min < 180) + text->setAttribute("text_align_horizontal", "left"); + else if (x_lim_min > 180) + text->setAttribute("text_align_horizontal", "right"); + if (x_lim_min < 90 || x_lim_min > 270) + text->setAttribute("text_align_vertical", "top"); + else if (x_lim_min == 90 || x_lim_min == 270) + text->setAttribute("text_align_vertical", "half"); + else if (x_lim_min > 90 && x_lim_min < 270) + text->setAttribute("text_align_vertical", "bottom"); + } + } + } + if (!with_pan) break; } - if (del != del_values::update_without_default && del != del_values::update_with_default) + } + + if (element->parentElement()->hasAttribute("char_height")) processCharHeight(element->parentElement()); + processLineType(element->parentElement()); + processTextAlign(element->parentElement()); +} + +static void processAngleLine(const std::shared_ptr &element, const std::shared_ptr &context) +{ + double text_x0 = 0.0, text_y0 = 0.0, factor = 1.1; + std::string angle_label; + del_values del = del_values::update_without_default; + int child_id = 0; + bool with_pan = false; + std::shared_ptr plot_parent = element, line, text; + getPlotParent(plot_parent); + + with_pan = + plot_parent->hasAttribute("polar_with_pan") && static_cast(plot_parent->getAttribute("polar_with_pan")); + if (with_pan) factor = 0.9; + + /* clear old angle_line elements */ + del = del_values(static_cast(element->getAttribute("_delete_children"))); + clearOldChildren(&del, element); + + global_render->setLineType(element, GKS_K_LINETYPE_SOLID); + + auto line_x0 = static_cast(element->getAttribute("x")); + auto line_y0 = static_cast(element->getAttribute("y")); + if (element->hasAttribute("angle_label")) + { + angle_label = static_cast(element->getAttribute("angle_label")); + if (!angle_label.empty()) { - text = render->createText(x[0], y[0], text_buffer, CoordinateSpace::WC); + if (!element->hasAttribute("text_x0")) throw NotFoundError("Missing text_x0 data for given angle_label!\n"); + text_x0 = static_cast(element->getAttribute("text_x0")); + if (!element->hasAttribute("text_y0")) throw NotFoundError("Missing text_y0 data for given angle_label!\n"); + text_y0 = static_cast(element->getAttribute("text_y0")); + } + } + + if (del != del_values::update_without_default && del != del_values::update_with_default) + { + line = global_render->createPolyline(line_x0, 0.0, line_y0, 0.0); + line->setAttribute("_child_id", child_id++); + element->append(line); + } + else + { + line = element->querySelectors("polyline[_child_id=" + std::to_string(child_id++) + "]"); + if (line != nullptr) global_render->createPolyline(line_x0, 0.0, line_y0, 0.0, 0, 0.0, 0, line); + } + if (line != nullptr) + { + if (del != del_values::update_without_default) global_render->setLineColorInd(line, 88); + } + + if (!angle_label.empty()) + { + if (with_pan) text = element->querySelectors("text[_child_id=" + std::to_string(child_id) + "]"); + if ((del != del_values::update_without_default && del != del_values::update_with_default) || + (with_pan && text == nullptr)) + { + text = global_render->createText(text_x0 * factor, text_y0 * factor, angle_label, CoordinateSpace::WC); text->setAttribute("_child_id", child_id++); element->append(text); } else { text = element->querySelectors("text[_child_id=" + std::to_string(child_id++) + "]"); - if (text != nullptr) render->createText(x[0], y[0], text_buffer, CoordinateSpace::WC, text); + if (text != nullptr) + global_render->createText(text_x0 * factor, text_y0 * factor, angle_label, CoordinateSpace::WC, text); } - if (text != nullptr) text->setAttribute("name", "polar_axes"); if (text != nullptr && del != del_values::update_without_default) - render->setTextAlign(text, GKS_K_TEXT_HALIGN_CENTER, GKS_K_TEXT_VALIGN_HALF); + { + global_render->setTextAlign(text, GKS_K_TEXT_HALIGN_CENTER, GKS_K_TEXT_VALIGN_HALF); + } } + else if (with_pan) + { + text = element->querySelectors("text[_child_id=" + std::to_string(child_id++) + "]"); + if (text != nullptr) element->removeChild(text); + } +} - // Draw Text - render->setTextAlign(element, GKS_K_TEXT_HALIGN_LEFT, GKS_K_TEXT_VALIGN_HALF); - std::shared_ptr axes_text_group = element->querySelectors("axes_text_group"); - if (axes_text_group == nullptr) +static void processThetaAxes(const std::shared_ptr &element, const std::shared_ptr &context) +{ + double window[4]; + char text_buffer[PLOT_POLAR_AXES_TEXT_BUFFER]; + std::string text; + double interval, factor = 1; + int angle_line_num = 8; + del_values del = del_values::update_without_default; + int child_id = 0; + bool skip_calculations = false, phi_flip = false, pass = false, with_pan = false; + double x_lim_min = 0, x_lim_max = 360; + std::shared_ptr central_region, plot_parent = element, axes_text_group; + + getPlotParent(plot_parent); + for (const auto &child : plot_parent->children()) + { + if (child->localName() == "central_region") + { + central_region = child; + break; + } + } + + window[0] = static_cast(central_region->getAttribute("window_x_min")); + window[1] = static_cast(central_region->getAttribute("window_x_max")); + window[2] = static_cast(central_region->getAttribute("window_y_min")); + window[3] = static_cast(central_region->getAttribute("window_y_max")); + + with_pan = + plot_parent->hasAttribute("polar_with_pan") && static_cast(plot_parent->getAttribute("polar_with_pan")); + if (with_pan) + factor = grm_max(abs(window[0]), grm_max(abs(window[1]), grm_max(abs(window[2]), abs(window[3])))) * sqrt(2); + + if (central_region->hasAttribute("_skip_calculations")) + { + skip_calculations = static_cast(central_region->getAttribute("_skip_calculations")); + central_region->removeAttribute("_skip_calculations"); + } + + if (!skip_calculations) calculatePolarLimits(central_region, context); + if (plot_parent->hasAttribute("phi_flip")) phi_flip = static_cast(plot_parent->getAttribute("phi_flip")); + if (plot_parent->hasAttribute("x_lim_min") && plot_parent->hasAttribute("x_lim_max")) + { + x_lim_min = static_cast(plot_parent->getAttribute("x_lim_min")); + x_lim_max = static_cast(plot_parent->getAttribute("x_lim_max")); + } + if (with_pan) { - axes_text_group = render->createElement("axes_text_group"); - element->append(axes_text_group); + x_lim_min = 0; + x_lim_max = 360; } + if (element->hasAttribute("angle_line_num")) + angle_line_num = static_cast(element->getAttribute("angle_line_num")); - for (i = 0; i <= n; i++) + global_render->setLineType(element, GKS_K_LINETYPE_SOLID); + + /* clear old theta_axes_elements */ + del = del_values(static_cast(element->getAttribute("_delete_children"))); + if (angle_line_num != 8) del = del_values::recreate_own_children; // could be improved + clearOldChildren(&del, element); + + // Draw sector lines + interval = 360.0 / angle_line_num; + for (int i = 0; i <= angle_line_num; i++) { - std::shared_ptr text; - double r = 1.0 / n * i; - if (i % 2 == 0 || i == n) + std::shared_ptr angle_line; + int text_number = 0; + double alpha = i * interval; + double x0 = std::cos(alpha * M_PI / 180.0), y0 = std::sin(alpha * M_PI / 180.0); + + if (alpha == 360 && x_lim_max == 360) continue; + if (alpha < x_lim_min && alpha + interval > x_lim_min) + { + x0 = std::cos(x_lim_min * M_PI / 180.0), y0 = std::sin(x_lim_min * M_PI / 180.0); + pass = true; + } + if (alpha > x_lim_max && alpha - interval < x_lim_max) { - x[0] = 0.05; - y[0] = r; - snprintf(text_buffer, PLOT_POLAR_AXES_TEXT_BUFFER, "%.1lf", r_min + tick * i); + x0 = std::cos(x_lim_max * M_PI / 180.0), y0 = std::sin(x_lim_max * M_PI / 180.0); + pass = true; + } + if (!with_pan) + { + x0 *= window[1]; + y0 *= window[3]; + } + + // define the number which will be stored inside the text + text_number = phi_flip ? 360 - (int)grm_round(alpha) : (int)grm_round(alpha); + snprintf(text_buffer, PLOT_POLAR_AXES_TEXT_BUFFER, "%d\xc2\xb0", text_number); + text = text_buffer; + if ((alpha >= x_lim_min && alpha <= x_lim_max) || pass) + { + if (pass) + { + text = ""; + gr_setclip(0); + } if (del != del_values::update_without_default && del != del_values::update_with_default) { - text = render->createText(x[0], y[0], text_buffer, CoordinateSpace::WC); - text->setAttribute("_child_id", child_id++); - axes_text_group->append(text); + angle_line = global_render->createAngleLine(x0 * factor, y0 * factor, text); + angle_line->setAttribute("_child_id", child_id++); + element->append(angle_line); } else { - text = element->querySelectors("text[_child_id=" + std::to_string(child_id++) + "]"); - if (text != nullptr) render->createText(x[0], y[0], text_buffer, CoordinateSpace::WC, text); + angle_line = element->querySelectors("angle_line[_child_id=" + std::to_string(child_id++) + "]"); + if (angle_line != nullptr) global_render->createAngleLine(x0 * factor, y0 * factor, text, angle_line); + } + if (angle_line != nullptr) + { + if (with_pan && + (window[0] >= x0 * 0.9 || x0 * 0.9 >= window[1] || window[2] >= y0 * 0.9 || y0 * 0.9 >= window[3])) + { + text = ""; + if (angle_line->hasAttribute("text_x0")) angle_line->removeAttribute("text_x0"); + if (angle_line->hasAttribute("text_y0")) angle_line->removeAttribute("text_y0"); + angle_line->setAttribute("angle_label", text); + } + else if (!text.empty()) + { + angle_line->setAttribute("text_x0", x0); + angle_line->setAttribute("text_y0", y0); + } + } + if (pass) + { + pass = false; + gr_setclip(1); } } } - if (element->hasAttribute("char_height")) - { - processCharHeight(element); - } - processLineType(element); - processTextAlign(element); + + if (element->parentElement()->hasAttribute("char_height")) processCharHeight(element->parentElement()); + processLineType(element->parentElement()); + processTextAlign(element->parentElement()); } static void processDrawRect(const std::shared_ptr &element, const std::shared_ptr &context) { /*! - * Processing function for drawArc + * Processing function for draw_rect * * \param[in] element The GRM::Element that contains the attributes and data keys * \param[in] context The GRM::Context that contains the actual data @@ -7524,7 +8372,7 @@ static void processDrawRect(const std::shared_ptr &element, const static void processFillArc(const std::shared_ptr &element, const std::shared_ptr &context) { /*! - * Processing function for drawArc + * Processing function for fill_arc * * \param[in] element The GRM::Element that contains the attributes and data keys * \param[in] context The GRM::Context that contains the actual data @@ -7542,7 +8390,7 @@ static void processFillArc(const std::shared_ptr &element, const s static void processFillRect(const std::shared_ptr &element, const std::shared_ptr &context) { /*! - * Processing function for drawArc + * Processing function for fill_rect * * \param[in] element The GRM::Element that contains the attributes and data keys * \param[in] context The GRM::Context that contains the actual data @@ -7682,15 +8530,9 @@ static void processHeatmap(const std::shared_ptr &element, const s { for (i = 0; i < cols; i++) { - if (grm_isnan(x_vec[i])) - { - x_vec.erase(x_vec.begin(), x_vec.begin() + 1); - x_offset += 1; - } - else - { - break; - } + if (!grm_isnan(x_vec[i])) break; + x_vec.erase(x_vec.begin(), x_vec.begin() + 1); + x_offset += 1; } cols = x_vec.size(); } @@ -7705,15 +8547,9 @@ static void processHeatmap(const std::shared_ptr &element, const s { for (i = 0; i < rows; i++) { - if (grm_isnan(y_vec[i])) - { - y_vec.erase(y_vec.begin(), y_vec.begin() + 1); - y_offset += 1; - } - else - { - break; - } + if (!grm_isnan(y_vec[i])) break; + y_vec.erase(y_vec.begin(), y_vec.begin() + 1); + y_offset += 1; } rows = y_vec.size(); } @@ -7854,14 +8690,7 @@ static void processHeatmap(const std::shared_ptr &element, const s else { data[i] = (int)((zv - c_min) / (c_max - c_min) * 255 + 0.5); - if (data[i] >= 255) - { - data[i] = 255; - } - else if (data[i] < 0) - { - data[i] = 0; - } + data[i] = grm_max(grm_min(data[i], 255), 0); // data values must be inside [0, 255] } } } @@ -7892,20 +8721,20 @@ static void processHeatmap(const std::shared_ptr &element, const s } } - std::shared_ptr cellarray; + std::shared_ptr cell_array; if (del != del_values::update_without_default && del != del_values::update_with_default) { - cellarray = + cell_array = global_render->createDrawImage(x_min, y_min, x_max, y_max, (int)cols, (int)rows, "rgba" + str, rgba, 0); - cellarray->setAttribute("_child_id", child_id++); - element->append(cellarray); + cell_array->setAttribute("_child_id", child_id++); + element->append(cell_array); } else { - cellarray = element->querySelectors("draw_image[_child_id=" + std::to_string(child_id++) + "]"); - if (cellarray != nullptr) + cell_array = element->querySelectors("draw_image[_child_id=" + std::to_string(child_id++) + "]"); + if (cell_array != nullptr) global_render->createDrawImage(x_min, y_min, x_max, y_max, (int)cols, (int)rows, "rgba" + str, rgba, 0, - nullptr, cellarray); + nullptr, cell_array); } } else @@ -7922,22 +8751,22 @@ static void processHeatmap(const std::shared_ptr &element, const s } } - std::shared_ptr cellarray; + std::shared_ptr cell_array; if (del != del_values::update_without_default && del != del_values::update_with_default) { - cellarray = + cell_array = global_render->createNonUniformCellArray("x" + str, x_vec, "y" + str, y_vec, (int)cols, (int)rows, 1, 1, (int)cols, (int)rows, "color_ind_values" + str, rgba); - cellarray->setAttribute("_child_id", child_id++); - element->append(cellarray); + cell_array->setAttribute("_child_id", child_id++); + element->append(cell_array); } else { - cellarray = element->querySelectors("nonuniformcellarray[_child_id=" + std::to_string(child_id++) + "]"); - if (cellarray != nullptr) + cell_array = element->querySelectors("nonuniform_cell_array[_child_id=" + std::to_string(child_id++) + "]"); + if (cell_array != nullptr) global_render->createNonUniformCellArray("x" + str, x_vec, "y" + str, y_vec, (int)cols, (int)rows, 1, 1, (int)cols, (int)rows, "color_ind_values" + str, rgba, nullptr, - cellarray); + cell_array); } } } @@ -7965,13 +8794,10 @@ static void hexbin(const std::shared_ptr &element, const std::shar { auto address = static_cast(element->getAttribute("_hexbin_context_address")); long hex_address = stol(address, nullptr, 16); - const hexbin_2pass_t *hexbinContext = (hexbin_2pass_t *)hex_address; - bool cleanup = hexbinContext->action & GR_2PASS_CLEANUP; - if (redraw_ws) gr_hexbin_2pass(x_length, x_p, y_p, nbins, hexbinContext); - if (cleanup) - { - element->removeAttribute("_hexbin_context_address"); - } + const hexbin_2pass_t *hexbin_context = (hexbin_2pass_t *)hex_address; + bool cleanup = hexbin_context->action & GR_2PASS_CLEANUP; + if (redraw_ws) gr_hexbin_2pass(x_length, x_p, y_p, nbins, hexbin_context); + if (cleanup) element->removeAttribute("_hexbin_context_address"); } else { @@ -8006,10 +8832,10 @@ static void processHexbin(const std::shared_ptr &element, const st auto y_length = (int)y_vec.size(); if (x_length != y_length) throw std::length_error("For Hexbin x- and y-data must have the same size\n."); - const hexbin_2pass_t *hexbinContext = gr_hexbin_2pass(x_length, x_p, y_p, nbins, nullptr); - double c_min = 0.0, c_max = hexbinContext->cntmax; + const hexbin_2pass_t *hexbin_context = gr_hexbin_2pass(x_length, x_p, y_p, nbins, nullptr); + double c_min = 0.0, c_max = hexbin_context->cntmax; std::ostringstream get_address; - get_address << hexbinContext; + get_address << hexbin_context; element->setAttribute("_hexbin_context_address", get_address.str()); auto plot_parent = element->parentElement(); @@ -8027,7 +8853,7 @@ static void histBins(const std::shared_ptr &element, const std::sh { double *tmp_bins; std::vector x, weights; - unsigned int num_bins = 0, num_weights; + unsigned int num_bins = 0, num_weights = 0; if (!element->hasAttribute("x")) throw NotFoundError("Hist series is missing required attribute x-data.\n"); auto key = static_cast(element->getAttribute("x")); @@ -8043,10 +8869,8 @@ static void histBins(const std::shared_ptr &element, const std::sh } if (!weights.empty() && current_point_count != num_weights) throw std::length_error("For hist series the size of data and weights must be the same.\n"); - if (num_bins <= 1) - { - num_bins = (int)(3.3 * log10(current_point_count) + 0.5) + 1; - } + + if (num_bins <= 1) num_bins = (int)(3.3 * log10(current_point_count) + 0.5) + 1; auto bins = std::vector(num_bins); double *x_p = &(x[0]); double *weights_p = (weights.empty()) ? nullptr : &(weights[0]); @@ -8080,7 +8904,7 @@ static void processHist(const std::shared_ptr &element, const std: double x_min, x_max, bar_width, y_min, y_max; std::vector bins_vec; unsigned int num_bins; - std::string orientation = PLOT_DEFAULT_ORIENTATION; + std::string orientation = PLOT_DEFAULT_ORIENTATION, line_spec = SERIES_DEFAULT_SPEC; bool is_horizontal; if (element->hasAttribute("fill_color_rgb")) @@ -8089,6 +8913,12 @@ static void processHist(const std::shared_ptr &element, const std: bar_color_rgb_vec = GRM::get>((*context)[bar_color_rgb]); } + // Todo: using line_spec here istn't really clean, cause no lines are drawn, but it's the only option atm to get the + // same different colors like multiple line series have + const char *spec_char = line_spec.c_str(); + gr_uselinespec((char *)spec_char); + gr_inqmarkercolorind(&bar_color_index); + if (element->hasAttribute("fill_color_ind")) bar_color_index = static_cast(element->getAttribute("fill_color_ind")); @@ -8149,7 +8979,10 @@ static void processHist(const std::shared_ptr &element, const std: x_max = static_cast(element->getAttribute("x_range_max")); y_min = static_cast(element->getAttribute("y_range_min")); y_max = static_cast(element->getAttribute("y_range_max")); + if (plot_parent->hasAttribute("_y_line_pos")) y_min = static_cast(plot_parent->getAttribute("_y_line_pos")); if (std::isnan(y_min)) y_min = 0.0; + if (plot_parent->hasAttribute("y_log") && static_cast(plot_parent->getAttribute("y_log")) && y_min < 0) + y_min = 1; if (element->parentElement()->parentElement()->hasAttribute("marginal_heatmap_side_plot")) { @@ -8246,9 +9079,8 @@ static void processHist(const std::shared_ptr &element, const std: static void processBar(const std::shared_ptr &element, const std::shared_ptr &context) { - bool is_horizontal; double x1, x2, y1, y2; - int bar_color_index, edge_color_index, text_color_index = -1, color_save_spot = PLOT_CUSTOM_COLOR_INDEX; + int bar_color_index, edge_color_index, color_save_spot = PLOT_CUSTOM_COLOR_INDEX; std::shared_ptr fill_rect, draw_rect, text_elem; std::string orientation = PLOT_DEFAULT_ORIENTATION, text; del_values del = del_values::update_without_default; @@ -8376,10 +9208,7 @@ static void processIsosurfaceRender(const std::shared_ptr &element double viewport[4]; double x_min, x_max, y_min, y_max; int fig_width, fig_height; - int subplot_width, subplot_height; - int drawable_type; - - drawable_type = static_cast(element->getAttribute("drawable_type")); + int plot_width, plot_height; gr_inqviewport(&viewport[0], &viewport[1], &viewport[2], &viewport[3]); @@ -8389,16 +9218,15 @@ static void processIsosurfaceRender(const std::shared_ptr &element y_max = viewport[3]; GRM::Render::getFigureSize(&fig_width, &fig_height, nullptr, nullptr); - subplot_width = (int)(grm_max(fig_width, fig_height) * (x_max - x_min)); - subplot_height = (int)(grm_max(fig_width, fig_height) * (y_max - y_min)); + plot_width = (int)(grm_max(fig_width, fig_height) * (x_max - x_min)); + plot_height = (int)(grm_max(fig_width, fig_height) * (y_max - y_min)); logger((stderr, "viewport: (%lf, %lf, %lf, %lf)\n", x_min, x_max, y_min, y_max)); logger((stderr, "viewport ratio: %lf\n", (x_min - x_max) / (y_min - y_max))); - logger((stderr, "subplot size: (%d, %d)\n", subplot_width, subplot_height)); - logger((stderr, "subplot ratio: %lf\n", ((double)subplot_width / (double)subplot_height))); + logger((stderr, "plot size: (%d, %d)\n", plot_width, plot_height)); + logger((stderr, "plot ratio: %lf\n", ((double)plot_width / (double)plot_height))); - gr3_drawimage((float)x_min, (float)x_max, (float)y_min, (float)y_max, subplot_width, subplot_height, - GR3_DRAWABLE_GKS); + gr3_drawimage((float)x_min, (float)x_max, (float)y_min, (float)y_max, plot_width, plot_height, GR3_DRAWABLE_GKS); } static void processLayoutGrid(const std::shared_ptr &element, @@ -8421,12 +9249,12 @@ static void processNonUniformPolarCellArray(const std::shared_ptr auto y_org = static_cast(element->getAttribute("y_org")); auto phi_key = static_cast(element->getAttribute("phi")); auto r_key = static_cast(element->getAttribute("r")); - auto dimr = static_cast(element->getAttribute("r_dim")); - auto dimphi = static_cast(element->getAttribute("phi_dim")); - auto scol = static_cast(element->getAttribute("start_col")); - auto srow = static_cast(element->getAttribute("start_row")); - auto ncol = static_cast(element->getAttribute("num_col")); - auto nrow = static_cast(element->getAttribute("num_row")); + auto dim_r = static_cast(element->getAttribute("r_dim")); + auto dim_phi = static_cast(element->getAttribute("phi_dim")); + auto s_col = static_cast(element->getAttribute("start_col")); + auto s_row = static_cast(element->getAttribute("start_row")); + auto n_col = static_cast(element->getAttribute("num_col")); + auto n_row = static_cast(element->getAttribute("num_row")); auto color_key = static_cast(element->getAttribute("color_ind_values")); auto r_vec = GRM::get>((*context)[r_key]); @@ -8438,14 +9266,14 @@ static void processNonUniformPolarCellArray(const std::shared_ptr int *color = &(color_vec[0]); applyMoveTransformation(element); - if (redraw_ws) gr_nonuniformpolarcellarray(x_org, y_org, phi, r, dimphi, dimr, scol, srow, ncol, nrow, color); + if (redraw_ws) gr_nonuniformpolarcellarray(x_org, y_org, phi, r, dim_phi, dim_r, s_col, s_row, n_col, n_row, color); } -static void processNonuniformcellarray(const std::shared_ptr &element, +static void processNonuniformCellArray(const std::shared_ptr &element, const std::shared_ptr &context) { /*! - * Processing function for nonuniformcellarray + * Processing function for nonuniform_cell_array * * \param[in] element The GRM::Element that contains the attributes and data keys * \param[in] context The GRM::Context that contains the actual data @@ -8479,16 +9307,16 @@ static void processPolarCellArray(const std::shared_ptr &element, { auto x_org = static_cast(element->getAttribute("x_org")); auto y_org = static_cast(element->getAttribute("y_org")); - auto phimin = static_cast(element->getAttribute("phi_min")); - auto phimax = static_cast(element->getAttribute("phi_max")); - auto rmin = static_cast(element->getAttribute("r_min")); - auto rmax = static_cast(element->getAttribute("r_max")); - auto dimr = static_cast(element->getAttribute("r_dim")); - auto dimphi = static_cast(element->getAttribute("phi_dim")); - auto scol = static_cast(element->getAttribute("start_col")); - auto srow = static_cast(element->getAttribute("start_row")); - auto ncol = static_cast(element->getAttribute("num_col")); - auto nrow = static_cast(element->getAttribute("num_row")); + auto phi_min = static_cast(element->getAttribute("phi_min")); + auto phi_max = static_cast(element->getAttribute("phi_max")); + auto r_min = static_cast(element->getAttribute("r_min")); + auto r_max = static_cast(element->getAttribute("r_max")); + auto dim_r = static_cast(element->getAttribute("r_dim")); + auto dim_phi = static_cast(element->getAttribute("phi_dim")); + auto s_col = static_cast(element->getAttribute("start_col")); + auto s_row = static_cast(element->getAttribute("start_row")); + auto n_col = static_cast(element->getAttribute("num_col")); + auto n_row = static_cast(element->getAttribute("num_row")); auto color_key = static_cast(element->getAttribute("color_ind_values")); auto color_vec = GRM::get>((*context)[color_key]); @@ -8496,7 +9324,7 @@ static void processPolarCellArray(const std::shared_ptr &element, applyMoveTransformation(element); if (redraw_ws) - gr_polarcellarray(x_org, y_org, phimin, phimax, rmin, rmax, dimphi, dimr, scol, srow, ncol, nrow, color); + gr_polarcellarray(x_org, y_org, phi_min, phi_max, r_min, r_max, dim_phi, dim_r, s_col, s_row, n_col, n_row, color); } static void processPolyline(const std::shared_ptr &element, const std::shared_ptr &context) @@ -8630,7 +9458,7 @@ static void processPolymarker3d(const std::shared_ptr &element, const std::shared_ptr &context) { /*! - * Processing function for polymarker 3d + * Processing function for polymarker_3d * * \param[in] element The GRM::Element that contains the attributes and data keys * \param[in] context The GRM::Context that contains the actual data @@ -8695,90 +9523,329 @@ static void processQuiver(const std::shared_ptr &element, const st if (x_length * y_length != v_length) throw std::length_error("For quiver series x_length * y_length must be v_length.\n"); - double *x_p = &(x_vec[0]); - double *y_p = &(y_vec[0]); - double *u_p = &(GRM::get>((*context)[u])[0]); - double *v_p = &(GRM::get>((*context)[v])[0]); - applyMoveTransformation(element); + double *x_p = &(x_vec[0]); + double *y_p = &(y_vec[0]); + double *u_p = &(GRM::get>((*context)[u])[0]); + double *v_p = &(GRM::get>((*context)[v])[0]); + applyMoveTransformation(element); + + if (redraw_ws) gr_quiver(x_length, y_length, x_p, y_p, u_p, v_p, color); +} + +void calculatePolarXAndY(std::vector &x, std::vector &y, const std::shared_ptr &element, + const std::shared_ptr &context) +{ + double r_min, r_max; + double y_lim_min, y_lim_max, y_range_min, y_range_max, x_range_min, x_range_max; + double theta_min, theta_max; + bool transform_radii = false, transform_angles = false, clip_negative = false, y_log = false; + unsigned int rho_length, theta_length; + unsigned int i, index = 0; + std::string kind; + std::vector theta_vec, rho_vec; + std::shared_ptr plot_parent = element, central_region; + getPlotParent(plot_parent); + + central_region = plot_parent->querySelectors("central_region"); + kind = static_cast(plot_parent->getAttribute("_kind")); + + if (!element->hasAttribute("x")) + throw NotFoundError(kind + " series is missing required attribute x-data (theta).\n"); + auto x_key = static_cast(element->getAttribute("x")); + if (!element->hasAttribute("y")) throw NotFoundError(kind + " series is missing required attribute y-data (rho).\n"); + auto y_key = static_cast(element->getAttribute("y")); + theta_vec = GRM::get>((*context)[x_key]); + rho_vec = GRM::get>((*context)[y_key]); + theta_length = theta_vec.size(); + rho_length = rho_vec.size(); + + if (plot_parent->hasAttribute("y_lim_max") && plot_parent->hasAttribute("y_lim_min")) + { + y_lim_min = static_cast(plot_parent->getAttribute("y_lim_min")); + y_lim_max = static_cast(plot_parent->getAttribute("y_lim_max")); + } + else + { + y_lim_min = static_cast(central_region->getAttribute("r_min")); + y_lim_max = static_cast(central_region->getAttribute("r_max")); + } + + if (element->hasAttribute("y_range_min") && element->hasAttribute("y_range_max")) + { + transform_radii = true; + y_range_min = static_cast(element->getAttribute("y_range_min")); + y_range_max = static_cast(element->getAttribute("y_range_max")); + } + + if (plot_parent->hasAttribute("y_log")) y_log = static_cast(plot_parent->getAttribute("y_log")); + if (y_log) + { + // apply y_log to lims so that the data can get the log10 applied + y_lim_min = log10(y_lim_min); + y_lim_max = log10(y_lim_max); + } + + if (element->hasAttribute("x_range_min") && element->hasAttribute("x_range_max")) + { + x_range_min = static_cast(element->getAttribute("x_range_min")); + x_range_max = static_cast(element->getAttribute("x_range_max")); + transform_angles = true; + + if (x_range_max > 2 * M_PI) + { + // convert from degrees to radians + x_range_max *= (M_PI / 180.0); + x_range_min *= (M_PI / 180.0); + } + } + + if (element->hasAttribute("clip_negative")) clip_negative = static_cast(element->getAttribute("clip_negative")); + + // negative radii or NAN are clipped before the transformation into specified y_range (also when y_log is given) + if (clip_negative || y_log) + { + std::vector indices_vec; + for (i = 0; i < rho_length; i++) + { + if (std::signbit(rho_vec[i]) || std::isnan(rho_vec[i])) indices_vec.insert(indices_vec.begin(), i); + if (clip_negative && y_log && rho_vec[i] <= 0) indices_vec.insert(indices_vec.begin(), i); + } + + for (auto ind : indices_vec) + { + rho_vec.erase(rho_vec.begin() + ind); + theta_vec.erase(theta_vec.begin() + ind); + } + indices_vec.clear(); + rho_length = rho_vec.size(); + theta_length = theta_vec.size(); + } + + // get the minima and maxima from the data for possible transformations + r_min = *std::min_element(rho_vec.begin(), rho_vec.end()); + r_max = *std::max_element(rho_vec.begin(), rho_vec.end()); + theta_min = *std::min_element(theta_vec.begin(), theta_vec.end()); + theta_max = *std::max_element(theta_vec.begin(), theta_vec.end()); + + // clip_negative is not compatible with user given ranges, it overwrites + if (clip_negative) + { + if (std::signbit(y_range_min)) + { + x_range_min = theta_min; + y_range_min = r_min; + } + if (std::signbit(x_range_max)) + { + x_range_max = theta_max; + y_range_max = r_max; + } + transform_radii = false; + transform_angles = false; + } + if (r_min == y_range_min && r_max == y_range_max) transform_radii = false; + if (theta_min == x_range_min && theta_max == x_range_max) transform_angles = false; + + if (rho_length != theta_length) + throw std::length_error("For " + kind + "series y(rho)- and x(theta)-data must have the same size.\n"); + x.resize(rho_length); + y.resize(rho_length); + + // transform angles into specified x_ranges if given + if (transform_angles) transformCoordinatesVector(theta_vec, theta_min, theta_max, x_range_min, x_range_max); + + // transform radii into y_range if given or log scale + for (i = 0; i < rho_length; i++) + { + double current_rho; + if (transform_radii || y_log) + { + double temp_rho = rho_vec[i]; + if (std::isnan(rho_vec[i])) continue; // skip NAN data + + if (y_log && !transform_radii) + { + current_rho = transformCoordinate(temp_rho, y_lim_min, y_lim_max, 0.0, 0.0, y_log); + } + else + { + current_rho = transformCoordinate(temp_rho, r_min, r_max, y_range_min, y_range_max, y_log); + } + } + else + { + if (rho_vec[i] < 0) + { + // iterate over rho_vec and for each negative value add 180 degrees in radian to the corresponding value + // in theta_vec and make the rho_vec value positive + theta_vec[i] += M_PI; + // if theta_vec[i] is bigger than 2 * PI, subtract 2 * PI + if (theta_vec[i] > 2 * M_PI) theta_vec[i] -= 2 * M_PI; + rho_vec[i] = -rho_vec[i]; + } + + current_rho = rho_vec[i]; + } + if (y_lim_max != 0.0) current_rho /= y_lim_max; + x[index] = current_rho * cos(theta_vec[index]); + y[index] = current_rho * sin(theta_vec[index]); + ++index; + } + x.resize(index); + y.resize(index); +} + +static void processPolarLine(const std::shared_ptr &element, const std::shared_ptr &context) +{ + /*! + * Processing function for polar_line + * + * \param[in] element The GRM::Element that contains the attributes and data keys + * \param[in] context The GRM::Context that contains the actual data + */ + std::vector x, y; + std::string line_spec = SERIES_DEFAULT_SPEC; + std::shared_ptr plot_parent = element; + del_values del = del_values::update_without_default; + int child_id = 0; + getPlotParent(plot_parent); + + if (element->hasAttribute("line_spec")) + line_spec = static_cast(element->getAttribute("line_spec")); + else + element->setAttribute("line_spec", line_spec); + + calculatePolarXAndY(x, y, element, context); + + auto id = static_cast(global_root->getAttribute("_id")); + auto str_id = std::to_string(id); + + /* clear old polylines */ + del = del_values(static_cast(element->getAttribute("_delete_children"))); + clearOldChildren(&del, element); + + const char *spec_char = line_spec.c_str(); + int mask = gr_uselinespec((char *)spec_char); + + if (int_equals_any(mask, 5, 0, 1, 3, 4, 5)) + { + std::shared_ptr line; + int current_line_color_ind; + gr_inqlinecolorind(¤t_line_color_ind); + + if (del != del_values::update_without_default && del != del_values::update_with_default) + { + line = global_render->createPolyline("x" + str_id, x, "y" + str_id, y); + line->setAttribute("_child_id", child_id++); + element->append(line); + } + else + { + line = element->querySelectors("polyline[_child_id=" + std::to_string(child_id++) + "]"); + if (line != nullptr) + global_render->createPolyline("x" + str_id, x, "y" + str_id, y, nullptr, 0, 0.0, 0, line); + } + if (line != nullptr && del != del_values::update_without_default) + line->setAttribute("line_color_ind", current_line_color_ind); + } + if (mask & 2) + { + std::shared_ptr marker; + int current_marker_color_ind; + gr_inqmarkercolorind(¤t_marker_color_ind); + + if (del != del_values::update_without_default && del != del_values::update_with_default) + { + marker = global_render->createPolymarker("x" + str_id, x, "y" + str_id, y); + marker->setAttribute("_child_id", child_id++); + element->append(marker); + } + else + { + marker = element->querySelectors("polymarker[_child_id=" + std::to_string(child_id++) + "]"); + if (marker != nullptr) + global_render->createPolymarker("x" + str_id, x, "y" + str_id, y, nullptr, 0, 0.0, 0, marker); + } + if (marker != nullptr) + { + marker->setAttribute("marker_color_ind", current_marker_color_ind); + marker->setAttribute("z_index", 2); - if (redraw_ws) gr_quiver(x_length, y_length, x_p, y_p, u_p, v_p, color); + if (element->hasAttribute("marker_type")) + { + marker->setAttribute("marker_type", static_cast(element->getAttribute("marker_type"))); + } + else + { + marker->setAttribute("marker_type", *previous_line_marker_type++); + if (*previous_line_marker_type == INT_MAX) previous_line_marker_type = plot_scatter_markertypes; + } + } + } + global_root->setAttribute("_id", id + 1); } -static void processPolar(const std::shared_ptr &element, const std::shared_ptr &context) +static void processPolarScatter(const std::shared_ptr &element, + const std::shared_ptr &context) { /*! - * Processing function for polar + * Processing function for polar_scatter * * \param[in] element The GRM::Element that contains the attributes and data keys * \param[in] context The GRM::Context that contains the actual data */ - double r_min, r_max, tick; - int n, i; - unsigned int rho_length, theta_length; - std::string line_spec = SERIES_DEFAULT_SPEC; - std::vector theta_vec, rho_vec; - auto plot_parent = element->parentElement(); + std::vector x, y; + std::shared_ptr plot_parent = element; del_values del = del_values::update_without_default; int child_id = 0; - + std::shared_ptr marker; + int current_marker_color_ind; getPlotParent(plot_parent); - r_min = static_cast(plot_parent->getAttribute("_y_lim_min")); - r_max = static_cast(plot_parent->getAttribute("_y_lim_max")); - - if (element->hasAttribute("line_spec")) - { - line_spec = static_cast(element->getAttribute("line_spec")); - } - else - { - element->setAttribute("line_spec", line_spec); - } - element->setAttribute("r_min", r_min); - element->setAttribute("r_max", r_max); - tick = 0.5 * autoTick(r_min, r_max); - n = (int)ceil((r_max - r_min) / tick); - r_max = r_min + n * tick; - - if (!element->hasAttribute("x")) throw NotFoundError("Polar series is missing required attribute x-data (theta).\n"); - auto x_key = static_cast(element->getAttribute("x")); - if (!element->hasAttribute("y")) throw NotFoundError("Polar series is missing required attribute y-data (rho).\n"); - auto y_key = static_cast(element->getAttribute("y")); - theta_vec = GRM::get>((*context)[x_key]); - rho_vec = GRM::get>((*context)[y_key]); - theta_length = theta_vec.size(); - rho_length = rho_vec.size(); - if (rho_length != theta_length) - throw std::length_error("For polar series y(rho)- and x(theta)-data must have the same size.\n"); - std::vector x(rho_length), y(rho_length); - for (i = 0; i < rho_length; ++i) - { - double current_rho = rho_vec[i] / r_max; - x[i] = current_rho * cos(theta_vec[i]); - y[i] = current_rho * sin(theta_vec[i]); - } + calculatePolarXAndY(x, y, element, context); auto id = static_cast(global_root->getAttribute("_id")); - global_root->setAttribute("_id", id + 1); + auto str_id = std::to_string(id); /* clear old polylines */ del = del_values(static_cast(element->getAttribute("_delete_children"))); + if (x.size() == 0 || y.size() == 0) del = del_values::recreate_own_children; clearOldChildren(&del, element); + if (x.size() == 0 || y.size() == 0) return; + + if (!element->hasAttribute("marker_type")) + { + element->setAttribute("marker_type", *previous_scatter_marker_type++); + if (*previous_scatter_marker_type == INT_MAX) + { + previous_scatter_marker_type = plot_scatter_markertypes; + } + } + processMarkerType(element); - std::shared_ptr line; if (del != del_values::update_without_default && del != del_values::update_with_default) { - line = global_render->createPolyline("x" + std::to_string(id), x, "y" + std::to_string(id), y); - line->setAttribute("_child_id", child_id++); - element->append(line); + marker = global_render->createPolymarker("x" + str_id, x, "y" + str_id, y); + marker->setAttribute("_child_id", child_id++); + element->append(marker); } else { - line = element->querySelectors("polyline[_child_id=" + std::to_string(child_id++) + "]"); - if (line != nullptr) - global_render->createPolyline("x" + std::to_string(id), x, "y" + std::to_string(id), y, nullptr, 0, 0.0, 0, - line); + marker = element->querySelectors("polymarker[_child_id=" + std::to_string(child_id++) + "]"); + if (marker != nullptr) + global_render->createPolymarker("x" + str_id, x, "y" + str_id, y, nullptr, 0, 0.0, 0, marker); + } + if (marker != nullptr) + { + gr_inqmarkercolorind(¤t_marker_color_ind); + marker->setAttribute("marker_color_ind", current_marker_color_ind); + if (element->hasAttribute("marker_size")) + { + auto marker_size = static_cast(element->getAttribute("marker_size")); + marker->setAttribute("marker_size", marker_size); + } } + global_root->setAttribute("_id", id + 1); } static void processPolarHeatmap(const std::shared_ptr &element, @@ -8795,13 +9862,14 @@ static void processPolarHeatmap(const std::shared_ptr &element, int icmap[256]; unsigned int i, cols, rows, z_length; double x_min, x_max, y_min, y_max, z_min, z_max, c_min, c_max, zv; - bool is_uniform_heatmap; + double x_range_min, x_range_max, y_range_min, y_range_max, z_range_min, z_range_max; + bool is_uniform_heatmap, z_range = false, transform = false, y_log = false; std::vector data; std::vector x_vec, y_vec, z_vec; del_values del = del_values::update_without_default; int child_id = 0; - std::shared_ptr central_region; - auto plot_parent = element->parentElement(); + double convert = 1.0; + std::shared_ptr central_region, plot_parent = element; getPlotParent(plot_parent); for (const auto &child : plot_parent->children()) @@ -8813,7 +9881,12 @@ static void processPolarHeatmap(const std::shared_ptr &element, } } - kind = static_cast(plot_parent->getAttribute("kind")); + kind = static_cast(plot_parent->getAttribute("_kind")); + if (plot_parent->hasAttribute("y_log")) y_log = static_cast(plot_parent->getAttribute("y_log")); + + // calculate polar limits (r_max) + calculatePolarLimits(central_region, context); + central_region->setAttribute("_skip_calculations", true); if (element->hasAttribute("x")) { @@ -8827,12 +9900,31 @@ static void processPolarHeatmap(const std::shared_ptr &element, y_vec = GRM::get>((*context)[y]); rows = y_vec.size(); } - if (!element->hasAttribute("z")) throw NotFoundError("Polar-heatmap series is missing required attribute z-data.\n"); auto z = static_cast(element->getAttribute("z")); z_vec = GRM::get>((*context)[z]); z_length = z_vec.size(); + if (element->hasAttribute("x_range_min") && element->hasAttribute("x_range_max")) + { + transform = true; + x_range_min = static_cast(element->getAttribute("x_range_min")); + x_range_max = static_cast(element->getAttribute("x_range_max")); + if (x_range_max <= 2 * M_PI) convert = 180.0 / M_PI; + } + if (element->hasAttribute("y_range_min") && element->hasAttribute("y_range_max")) + { + transform = true; + y_range_min = static_cast(element->getAttribute("y_range_min")); + y_range_max = static_cast(element->getAttribute("y_range_max")); + } + if (element->hasAttribute("z_range_min") && element->hasAttribute("z_range_max")) + { + z_range = true; + z_range_min = static_cast(element->getAttribute("z_range_min")); + z_range_max = static_cast(element->getAttribute("z_range_max")); + } + if (x_vec.empty() && y_vec.empty()) { /* If neither `x` nor `y` are given, we need more information about the shape of `z` */ @@ -8853,15 +9945,15 @@ static void processPolarHeatmap(const std::shared_ptr &element, } is_uniform_heatmap = is_equidistant_array(cols, x_vec.data()) && is_equidistant_array(rows, y_vec.data()); - if (kind == "nonuniformpolar_heatmap") is_uniform_heatmap = false; + if (kind == "nonuniform_polar_heatmap") is_uniform_heatmap = false; if (!is_uniform_heatmap && (x_vec.empty() || y_vec.empty())) throw NotFoundError("Polar-heatmap series is missing x- or y-data or the data has to be uniform.\n"); if (x_vec.empty()) { - x_min = static_cast(element->getAttribute("x_range_min")); - x_max = static_cast(element->getAttribute("x_range_max")); + x_min = x_range_min; + x_max = x_range_max; } else { @@ -8870,8 +9962,8 @@ static void processPolarHeatmap(const std::shared_ptr &element, } if (y_vec.empty()) { - y_min = static_cast(element->getAttribute("y_range_min")); - y_max = static_cast(element->getAttribute("y_range_max")); + y_min = y_range_min; + y_max = y_range_max; } else { @@ -8879,6 +9971,60 @@ static void processPolarHeatmap(const std::shared_ptr &element, y_max = y_vec[rows - 1]; } + double r_max = static_cast(central_region->getAttribute("r_max")); + if (y_min > 0.0) is_uniform_heatmap = false; + + // Check if coordinate transformations are needed and then transform if needed + if (transform && ((!x_vec.empty() && (x_vec[0] < x_range_min || x_vec[x_vec.size() - 1] > x_range_max)) || + (!y_vec.empty() && (y_vec[0] < y_range_min || y_vec[y_vec.size() - 1] > y_range_max)))) + { + auto id = static_cast(global_root->getAttribute("_id")); + global_root->setAttribute("_id", id + 1); + auto str = std::to_string(id); + is_uniform_heatmap = false; + + if (x_vec.empty()) + { + x_vec.resize(cols); + for (int col = 0; col < cols; col++) + { + x_vec[col] = transformCoordinate(col / (cols - 1.0) * 360.0, 0.0, 360.0, x_range_min * convert, + x_range_max * convert); + } + (*context)["x" + str] = x_vec; + element->setAttribute("x", "x" + str); + } + else + { + transformCoordinatesVector(x_vec, x_min, x_max, x_range_min * convert, x_range_max * convert); + } + if (y_vec.empty()) + { + y_vec.resize(rows); + for (int row = 0; row < rows; row++) + { + y_vec[row] = transformCoordinate(row / (rows - 1.0), 0.0, 1.0, y_range_min, y_range_max); + } + (*context)["y" + str] = y_vec; + element->setAttribute("y", "y" + str); + } + else + { + transformCoordinatesVector(y_vec, y_min, y_max, y_range_min, y_range_max); + } + } + + if (z_range) + { + double min_val = *std::min_element(z_vec.begin(), z_vec.end()); + double max_val = *std::max_element(z_vec.begin(), z_vec.end()); + + for (int elem = 0; elem < rows * cols; ++elem) + { + z_vec[elem] = z_range_min + (z_range_max - z_range_min) * (z_vec[elem] - min_val) / (max_val - min_val); + } + } + z_min = static_cast(element->getAttribute("z_range_min")); z_max = static_cast(element->getAttribute("z_range_max")); if (!element->hasAttribute("c_range_min") || !element->hasAttribute("c_range_max")) @@ -8894,7 +10040,7 @@ static void processPolarHeatmap(const std::shared_ptr &element, for (i = 0; i < 256; i++) { - gr_inqcolor(1000 + i, icmap + i); + gr_inqcolor(1000 + (int)i, icmap + i); } data = std::vector(rows * cols); @@ -8911,14 +10057,7 @@ static void processPolarHeatmap(const std::shared_ptr &element, else { data[i] = 1000 + (int)(255.0 * (zv - c_min) / (c_max - c_min) + 0.5); - if (data[i] >= 1255) - { - data[i] = 1255; - } - else if (data[i] < 1000) - { - data[i] = 1000; - } + data[i] = grm_max(grm_min(data[i], 1255), 1000); } } } @@ -8930,6 +10069,9 @@ static void processPolarHeatmap(const std::shared_ptr &element, } } + // for cases like y_max = 3.2342 -> calc new r_max = 4.0 and use nonuniform_polar_cell_array + if (y_max != r_max) is_uniform_heatmap = false; + auto id = static_cast(global_root->getAttribute("_id")); global_root->setAttribute("_id", id + 1); auto str = std::to_string(id); @@ -8938,60 +10080,71 @@ static void processPolarHeatmap(const std::shared_ptr &element, del = del_values(static_cast(element->getAttribute("_delete_children"))); clearOldChildren(&del, element); - std::shared_ptr polar_cellarray; + if (y_log) is_uniform_heatmap = false; + + std::shared_ptr polar_cell_array; if (is_uniform_heatmap) { if (del != del_values::update_without_default && del != del_values::update_with_default) { - polar_cellarray = global_render->createPolarCellArray(0, 0, 0, 360, 0, 1, (int)cols, (int)rows, 1, 1, - (int)cols, (int)rows, "color_ind_values" + str, data); - polar_cellarray->setAttribute("_child_id", child_id++); - element->append(polar_cellarray); + polar_cell_array = global_render->createPolarCellArray(0, 0, 0, 360, 0, 1, (int)cols, (int)rows, 1, 1, + (int)cols, (int)rows, "color_ind_values" + str, data); + polar_cell_array->setAttribute("_child_id", child_id++); + element->append(polar_cell_array); } else { - polar_cellarray = element->querySelectors("polarcellarray[_child_id=" + std::to_string(child_id++) + "]"); - if (polar_cellarray != nullptr) + polar_cell_array = element->querySelectors("polar_cell_array[_child_id=" + std::to_string(child_id++) + "]"); + if (polar_cell_array != nullptr) global_render->createPolarCellArray(0, 0, 0, 360, 0, 1, (int)cols, (int)rows, 1, 1, (int)cols, (int)rows, - "color_ind_values" + str, data, nullptr, polar_cellarray); + "color_ind_values" + str, data, nullptr, polar_cell_array); } } else { - y_min = static_cast(central_region->getAttribute("window_y_min")); - y_max = static_cast(central_region->getAttribute("window_y_max")); + if (central_region->hasAttribute("r_max")) y_max = static_cast(central_region->getAttribute("r_max")); + if (x_vec[cols - 1] <= 2 * M_PI) convert = 180.0 / M_PI; - std::vector rho, phi; - for (i = 0; i < ((cols > rows) ? cols : rows); ++i) + std::vector rho(rows), phi(cols); + for (i = 0; i < ((cols > rows) ? cols : rows); i++) { - if (i < cols) - { - phi.push_back(x_vec[i] * 180 / M_PI); - } + if (i < cols) phi[i] = x_vec[i] * convert; if (i < rows) { - rho.push_back(y_min + y_vec[i] / (y_max - y_min)); + if (y_log) + { + rho[i] = (y_vec[i] <= 0) ? NAN : log10(y_vec[i]) / log10(y_max); + } + else + { + rho[i] = y_vec[i] / y_max; + } } } if (del != del_values::update_without_default && del != del_values::update_with_default) { - polar_cellarray = global_render->createNonUniformPolarCellArray(0, 0, "phi" + str, phi, "rho" + str, rho, - (int)-cols, (int)-rows, 1, 1, (int)cols, - (int)rows, "color_ind_values" + str, data); - polar_cellarray->setAttribute("_child_id", child_id++); - element->append(polar_cellarray); + polar_cell_array = global_render->createNonUniformPolarCellArray(0, 0, "phi" + str, phi, "rho" + str, rho, + (int)-cols, (int)-rows, 1, 1, (int)cols, + (int)rows, "color_ind_values" + str, data); + polar_cell_array->setAttribute("_child_id", child_id++); + element->append(polar_cell_array); } else { - polar_cellarray = - element->querySelectors("nonuniform_polarcellarray[_child_id=" + std::to_string(child_id++) + "]"); - if (polar_cellarray != nullptr) + polar_cell_array = + element->querySelectors("nonuniform_polar_cell_array[_child_id=" + std::to_string(child_id++) + "]"); + if (polar_cell_array != nullptr) global_render->createNonUniformPolarCellArray(0, 0, "phi" + str, phi, "rho" + str, rho, (int)-cols, (int)-rows, 1, 1, (int)cols, (int)rows, - "color_ind_values" + str, data, nullptr, polar_cellarray); + "color_ind_values" + str, data, nullptr, polar_cell_array); } } + if (!plot_parent->hasAttribute("polar_with_pan") || !static_cast(plot_parent->getAttribute("polar_with_pan"))) + { + global_render->setClipRegion(polar_cell_array, 1); + global_render->setSelectSpecificXform(polar_cell_array, 1); + } } static void preBarplot(const std::shared_ptr &element, const std::shared_ptr &context) @@ -9024,26 +10177,19 @@ static void preBarplot(const std::shared_ptr &element, const std:: element->setAttribute("max_y_length", max_y_length); } -static void prePolarHistogram(const std::shared_ptr &element, +static void prePolarHistogram(const std::shared_ptr &plot_elem, const std::shared_ptr &context) { - unsigned int num_bins, length, num_bin_edges, dummy; + unsigned int num_bins, length, num_bin_edges = 0, i; std::vector theta; std::string norm = "count"; std::vector classes, bin_counts; - double interval, start, max, temp_max, bin_width; - double *p, *phi_lim = nullptr; + double r_max, temp_max, bin_width, x_range_min, x_range_max; + double *phi_lim = nullptr; int max_observations = 0, total_observations = 0; - std::vector bin_edges, bin_widths; + std::vector bin_edges, bin_widths, new_theta, new_edges; bool is_bin_counts = false; - double phi_lim_arr[2]; - std::vector new_theta, new_edges; - - // element is the plot element -> get the first series with polar_histogram - auto series_list = element->querySelectorsAll("series_polar_histogram"); - std::shared_ptr group = series_list[0]; - // element = plot_group for better readability - const std::shared_ptr &plot_group = element; + std::shared_ptr series = plot_elem->querySelectorsAll("series_polar_histogram")[0]; // define keys for later usages auto id = static_cast(global_root->getAttribute("_id")); @@ -9051,98 +10197,103 @@ static void prePolarHistogram(const std::shared_ptr &element, global_root->setAttribute("_id", id + 1); std::string bin_widths_key = "bin_widths" + str, bin_edges_key = "bin_edges" + str, classes_key = "classes" + str; - if (group->hasAttribute("bin_counts")) + if (series->hasAttribute("bin_counts")) { is_bin_counts = true; - auto bin_counts_key = static_cast(group->getAttribute("bin_counts")); + auto bin_counts_key = static_cast(series->getAttribute("bin_counts")); bin_counts = GRM::get>((*context)[bin_counts_key]); length = bin_counts.size(); num_bins = length; - group->setAttribute("num_bins", static_cast(num_bins)); + series->setAttribute("num_bins", static_cast(num_bins)); } - else if (group->hasAttribute("theta")) + else if (series->hasAttribute("theta")) { - auto theta_key = static_cast(group->getAttribute("theta")); + auto theta_key = static_cast(series->getAttribute("theta")); theta = GRM::get>((*context)[theta_key]); length = theta.size(); + + if (series->hasAttribute("x_range_min") && series->hasAttribute("x_range_max")) + { + x_range_min = static_cast(series->getAttribute("x_range_min")); + x_range_max = static_cast(series->getAttribute("x_range_max")); + // convert x_range_min and max to radian if x_range_max > 2 * M_PI + if (x_range_max > 2 * M_PI) + { + x_range_min *= (M_PI / 180); + x_range_max *= (M_PI / 180); + } + if (x_range_min > x_range_max) std::swap(x_range_min, x_range_max); + + double theta_min = *std::min_element(theta.begin(), theta.end()); + double theta_max = *std::max_element(theta.begin(), theta.end()); + transformCoordinatesVector(theta, theta_min, theta_max, x_range_min, x_range_max); + } + } + else + { + throw NotFoundError("Polar histogram series is missing data theta or bin_counts\n"); } - if (plot_group->hasAttribute("phi_lim_min") || plot_group->hasAttribute("phi_lim_max")) + if (plot_elem->hasAttribute("phi_lim_min") || plot_elem->hasAttribute("phi_lim_max")) { + double phi_lim_arr[2]; phi_lim = phi_lim_arr; - phi_lim[0] = static_cast(plot_group->getAttribute("phi_lim_min")); - phi_lim[1] = static_cast(plot_group->getAttribute("phi_lim_max")); + phi_lim[0] = static_cast(plot_elem->getAttribute("phi_lim_min")); + phi_lim[1] = static_cast(plot_elem->getAttribute("phi_lim_max")); if (phi_lim[1] < phi_lim[0]) { std::swap(phi_lim[0], phi_lim[1]); - plot_group->setAttribute("phi_flip", 1); + plot_elem->setAttribute("phi_flip", true); } if (phi_lim[0] < 0.0 || phi_lim[1] > 2 * M_PI) logger((stderr, "\"phi_lim\" must be between 0 and 2 * pi\n")); - plot_group->setAttribute("phi_lim_min", phi_lim[0]); - plot_group->setAttribute("phi_lim_max", phi_lim[1]); + plot_elem->setAttribute("phi_lim_min", phi_lim[0]); + plot_elem->setAttribute("phi_lim_max", phi_lim[1]); } /* bin_edges and num_bins */ - if (!group->hasAttribute("bin_edges")) + if (!series->hasAttribute("bin_edges")) { - if (!group->hasAttribute("num_bins")) + if (series->hasAttribute("num_bins")) num_bins = static_cast(series->getAttribute("num_bins")); + if (!series->hasAttribute("num_bins") || num_bins <= 0 || num_bins > 200) { num_bins = grm_min(12, (int)(length / 2.0) - 1); - group->setAttribute("num_bins", static_cast(num_bins)); - } - else - { - num_bins = static_cast(group->getAttribute("num_bins")); - if (num_bins <= 0 || num_bins > 200) - { - num_bins = grm_min(12, (int)(length / 2.0) - 1); - group->setAttribute("num_bins", static_cast(num_bins)); - } + series->setAttribute("num_bins", static_cast(num_bins)); } - // check phi_lim again - if (phi_lim == nullptr) - num_bin_edges = 0; - else + + if (phi_lim != nullptr) { // if phi_lim is given, it will create equidistant bin_edges from phi_min to phi_max bin_edges.resize(num_bins + 1); linspace(phi_lim[0], phi_lim[1], (int)num_bins + 1, bin_edges); num_bin_edges = num_bins + 1; (*context)[bin_edges_key] = bin_edges; - group->setAttribute("bin_edges", bin_edges_key); + series->setAttribute("bin_edges", bin_edges_key); } } - else /* with bin_edges */ + else { int cnt = 0; - bin_edges_key = static_cast(group->getAttribute("bin_edges")); + bin_edges_key = static_cast(series->getAttribute("bin_edges")); bin_edges = GRM::get>((*context)[bin_edges_key]); num_bin_edges = bin_edges.size(); /* filter bin_edges */ new_edges.resize(num_bin_edges); - for (int i = 0; i < num_bin_edges; ++i) + for (i = 0; i < num_bin_edges; i++) { - if (phi_lim == nullptr) /* no phi_lim */ + // only use values for new_edges which are included inside the definition area + if ((phi_lim == nullptr && 0.0 <= bin_edges[i] && bin_edges[i] <= 2 * M_PI) || + (phi_lim != nullptr && phi_lim[0] <= bin_edges[i] && bin_edges[i] <= phi_lim[1])) { - if (0.0 <= bin_edges[i] && bin_edges[i] <= 2 * M_PI) - { - new_edges[cnt++] = bin_edges[i]; - } - else - { - logger((stderr, "Only values between 0 and 2 * pi allowed\n")); - } + new_edges[cnt++] = bin_edges[i]; } else { - if (phi_lim[0] <= bin_edges[i] && bin_edges[i] <= phi_lim[1]) - { - new_edges[cnt++] = bin_edges[i]; - } + logger((stderr, "Only values between the defined phi_lims or 0 and 2 * pi, if there are no phi_lims, are " + "allowed\n")); } } if (num_bin_edges > cnt) @@ -9154,60 +10305,60 @@ static void prePolarHistogram(const std::shared_ptr &element, { bin_edges = new_edges; } - if (phi_lim == nullptr) /* no phi_lim */ + if (phi_lim == nullptr) { num_bins = num_bin_edges - 1; - group->setAttribute("num_bins", static_cast(num_bins)); + series->setAttribute("num_bins", static_cast(num_bins)); } - else /* with phi_lim and bin_edges */ + else { - if (num_bin_edges == 1) + if (num_bin_edges != 1) { - logger((stderr, "Given \"phi_lim\" and given \"bin_edges\" are not compatible --> filtered " - "\"len(bin_edges) == 1\"\n")); + num_bins = num_bin_edges - 1; + series->setAttribute("num_bins", static_cast(num_bins)); + series->setAttribute("bin_edges", bin_edges_key); + (*context)[bin_edges_key] = bin_edges; } else { - num_bins = num_bin_edges - 1; - group->setAttribute("num_bins", static_cast(num_bins)); - group->setAttribute("bin_edges", bin_edges_key); - (*context)[bin_edges_key] = bin_edges; + logger((stderr, "Given \"phi_lim\" and given \"bin_edges\" are not compatible --> filtered " + "\"len(bin_edges) == 1\"\n")); } } } - if (group->hasAttribute("norm")) + if (series->hasAttribute("norm")) { - norm = static_cast(group->getAttribute("norm")); + norm = static_cast(series->getAttribute("norm")); if (!str_equals_any(norm, "count", "countdensity", "pdf", "probability", "cumcount", "cdf")) { logger((stderr, "Got keyword \"norm\" with invalid value \"%s\"\n", norm.c_str())); } } - if (!group->hasAttribute("bin_width")) + if (!series->hasAttribute("bin_width")) { if (num_bin_edges > 0) { bin_widths.resize(num_bins + 1); - for (int i = 1; i <= num_bin_edges - 1; ++i) + for (i = 1; i <= num_bin_edges - 1; i++) { bin_widths[i - 1] = bin_edges[i] - bin_edges[i - 1]; } - group->setAttribute("bin_widths", bin_widths_key); + series->setAttribute("bin_widths", bin_widths_key); (*context)[bin_widths_key] = bin_widths; } else { - bin_width = 2 * M_PI / num_bins; - group->setAttribute("bin_width", bin_width); + bin_width = 2.0 * M_PI / num_bins; + series->setAttribute("bin_width", bin_width); } } - else /* bin_width is given */ + else { int n = 0; - bin_width = static_cast(group->getAttribute("bin_width")); + bin_width = static_cast(series->getAttribute("bin_width")); if (num_bin_edges > 0 && phi_lim == nullptr) { @@ -9215,18 +10366,17 @@ static void prePolarHistogram(const std::shared_ptr &element, bin_widths.resize(num_bins); - for (int i = 1; i <= num_bin_edges - 1; ++i) + for (i = 1; i <= num_bin_edges - 1; i++) { bin_widths[i - 1] = bin_edges[i] - bin_edges[i - 1]; } - group->setAttribute("bin_widths", bin_widths_key); + series->setAttribute("bin_widths", bin_widths_key); (*context)[bin_widths_key] = bin_widths; } if (bin_width <= 0 || bin_width > 2 * M_PI) logger((stderr, "\"bin_width\" must be between 0 (exclusive) and 2 * pi\n")); - /* with phi_lim (with bin_width) */ if (phi_lim != nullptr) { if (phi_lim[1] - phi_lim[0] < bin_width) @@ -9247,7 +10397,7 @@ static void prePolarHistogram(const std::shared_ptr &element, linspace(phi_lim[0], n * bin_width, n + 1, bin_edges); } } - else /* without phi_lim */ + else { if ((int)(2 * M_PI / bin_width) > 200) { @@ -9265,35 +10415,33 @@ static void prePolarHistogram(const std::shared_ptr &element, bin_edges.resize(n + 1); linspace(0.0, n * bin_width, n + 1, bin_edges); } - group->setAttribute("num_bins", n); - num_bin_edges = n + 1; num_bins = n; - group->setAttribute("bin_edges", bin_edges_key); + series->setAttribute("num_bins", (int)num_bins); + num_bin_edges = n + 1; + series->setAttribute("bin_edges", bin_edges_key); (*context)[bin_edges_key] = bin_edges; - group->setAttribute("bin_width", bin_width); + series->setAttribute("bin_width", bin_width); bin_widths.resize(num_bins); - for (int i = 0; i < num_bins; ++i) + for (i = 0; i < num_bins; i++) { bin_widths[i] = bin_width; } - group->setAttribute("bin_widths", bin_widths_key); + series->setAttribute("bin_widths", bin_widths_key); (*context)[bin_widths_key] = bin_widths; } - /* is_bin_counts */ if (is_bin_counts) { double temp_max_bc = 0.0; - int i, j, total = 0, prev = 0; if (num_bin_edges > 0 && num_bins != num_bin_edges - 1) { logger((stderr, "Number of bin_edges must be number of bin_counts + 1\n")); } - total = std::accumulate(bin_counts.begin(), bin_counts.end(), 0); - for (i = 0; i < num_bins; ++i) + auto total = std::accumulate(bin_counts.begin(), bin_counts.end(), 0); + for (i = 0; i < num_bins; i++) { // temp_max_bc is a potential maximum for all bins respecting the given norm if (num_bin_edges > 0) bin_width = bin_widths[i]; @@ -9322,22 +10470,22 @@ static void prePolarHistogram(const std::shared_ptr &element, classes = bin_counts; } - group->setAttribute("classes", classes_key); + series->setAttribute("classes", classes_key); (*context)[classes_key] = classes; - group->setAttribute("total", total); + series->setAttribute("total", total); if (norm == "probability") - max = temp_max_bc * 1.0 / total; + r_max = temp_max_bc * 1.0 / total; else if (norm == "cdf") - max = 1.0; + r_max = 1.0; else if (norm == "cumcount") - max = total * 1.0; + r_max = total * 1.0; else - max = temp_max_bc; + r_max = temp_max_bc; } else /* no is_bin_counts */ { - max = 0.0; + r_max = 0.0; classes.resize(num_bins); // prepare bin_edges @@ -9347,7 +10495,7 @@ static void prePolarHistogram(const std::shared_ptr &element, bin_edges.resize(num_bins + 1); linspace(0.0, 2 * M_PI, (int)num_bins + 1, bin_edges); } - else // bin_edges given + else { // filter theta double edge_min = bin_edges[0], edge_max = bin_edges[num_bin_edges - 1]; @@ -9380,18 +10528,18 @@ static void prePolarHistogram(const std::shared_ptr &element, // get maximum number of observation from all bins max_observations = *std::max_element(classes.begin(), classes.end()); - group->setAttribute("classes", classes_key); + series->setAttribute("classes", classes_key); (*context)[classes_key] = classes; - group->setAttribute("total", total_observations); + series->setAttribute("total", total_observations); - // calculate the maximum from maxObservations respecting the norms + // calculate the maximum from max_observations respecting the norms if (num_bin_edges == 0 && norm == "pdf") // no given bin_edges { - max = max_observations * 1.0 / (total_observations * bin_width); + r_max = max_observations * 1.0 / (total_observations * bin_width); } else if (num_bin_edges != 0 && str_equals_any(norm, "pdf", "countdensity")) // calc maximum with given bin_edges { - for (int i = 0; i < num_bins; ++i) + for (i = 0; i < num_bins; i++) { // temporary maximum respecting norm temp_max = classes[i]; @@ -9400,43 +10548,40 @@ static void prePolarHistogram(const std::shared_ptr &element, else if (norm == "countdensity") temp_max /= bin_widths[i]; - if (temp_max > max) max = temp_max; + if (temp_max > r_max) r_max = temp_max; } } else if (str_equals_any(norm, "probability", "cdf")) { - max = max_observations * 1.0 / total_observations; + r_max = max_observations * 1.0 / total_observations; } else { - max = max_observations * 1.0; + r_max = (double)max_observations; } - } /* end classes and maximum */ - // set r_max (radius_max) in parent for later usages in polar_axes and polar_histogram - group->parentElement()->setAttribute("r_max", max); + } + // set r_max (radius_max) in parent for later usages for polar axes and polar_histogram + series->parentElement()->setAttribute("r_max", r_max); } static void processPolarHistogram(const std::shared_ptr &element, const std::shared_ptr &context) { unsigned int num_bins, num_bin_edges = 0; - int edge_color = 1, face_color = 989; - int total_observations = 0; - int xcolormap = -2, ycolormap = -2; - int child_id = 0; - double face_alpha = 0.75, bin_width = -1.0, max; + int edge_color = 1, face_color = 989, total_observations = 0; + int x_colormap = -2, y_colormap = -2; + int child_id = 0, i; + double transparency = 0.75, bin_width = -1.0; double r_min = 0.0, r_max = 1.0; - double *r_lim = nullptr, *phi_lim = nullptr; - double phi_lim_arr[2]; - bool draw_edges = false, stairs = false, phiflip = false; + double *phi_lim = nullptr; + double y_lim_min, y_lim_max; + bool draw_edges = false, stairs = false, phi_flip = false, keep_radii_axes = false, ylims = false, y_log = false; std::string norm = "count"; - std::vector r_lim_vec; - std::vector bin_edges, bin_widths; - std::vector mlist, rectlist; + std::vector r_lim_vec, bin_edges, bin_widths, rect_list; std::vector classes; + del_values del = del_values::update_without_default; std::shared_ptr plot_group = element->parentElement(); getPlotParent(plot_group); - del_values del = del_values::update_without_default; auto classes_key = static_cast(element->getAttribute("classes")); classes = GRM::get>((*context)[classes_key]); @@ -9445,20 +10590,39 @@ static void processPolarHistogram(const std::shared_ptr &element, del = del_values(static_cast(element->getAttribute("_delete_children"))); clearOldChildren(&del, element); + if (plot_group->hasAttribute("y_log")) y_log = static_cast(plot_group->getAttribute("y_log")); + if (element->hasAttribute("line_color_ind")) edge_color = static_cast(element->getAttribute("line_color_ind")); if (element->hasAttribute("color_ind")) face_color = static_cast(element->getAttribute("color_ind")); - if (element->hasAttribute("face_alpha")) face_alpha = static_cast(element->getAttribute("face_alpha")); + if (element->hasAttribute("transparency")) transparency = static_cast(element->getAttribute("transparency")); if (element->hasAttribute("norm")) norm = static_cast(element->getAttribute("norm")); - if (plot_group->hasAttribute("phi_flip")) phiflip = static_cast(plot_group->getAttribute("phi_flip")); + if (plot_group->hasAttribute("phi_flip")) phi_flip = static_cast(plot_group->getAttribute("phi_flip")); if (element->hasAttribute("draw_edges")) draw_edges = static_cast(element->getAttribute("draw_edges")); num_bins = static_cast(element->getAttribute("num_bins")); - max = static_cast(element->parentElement()->getAttribute("r_max")); + r_max = static_cast(element->parentElement()->getAttribute("r_max")); + if (y_log) r_max = log10(r_max); total_observations = static_cast(element->getAttribute("total")); - global_render->setTransparency(element, face_alpha); + global_render->setTransparency(element, transparency); processTransparency(element); + if (plot_group->hasAttribute("y_lim_min") && (plot_group->hasAttribute("y_lim_max"))) + { + ylims = true; + y_lim_min = static_cast(plot_group->getAttribute("y_lim_min")); + y_lim_max = static_cast(plot_group->getAttribute("y_lim_max")); + + if (y_log) + { + y_lim_min = log10(y_lim_min); + y_lim_max = log10(y_lim_max); + } + + if (plot_group->hasAttribute("keep_radii_axes")) + keep_radii_axes = static_cast(plot_group->getAttribute("keep_radii_axes")); + } if (plot_group->hasAttribute("phi_lim_min") || plot_group->hasAttribute("phi_lim_max")) { + double phi_lim_arr[2]; phi_lim = phi_lim_arr; phi_lim[0] = static_cast(plot_group->getAttribute("phi_lim_min")); phi_lim[1] = static_cast(plot_group->getAttribute("phi_lim_max")); @@ -9481,120 +10645,72 @@ static void processPolarHistogram(const std::shared_ptr &element, if (element->hasAttribute("stairs")) { - /* Set default stairs line color width and alpha values */ - if (!element->hasAttribute("face_alpha")) element->setAttribute("face_alpha", 1.0); + /* Set default stairs alpha values */ + if (!element->hasAttribute("transparency")) element->setAttribute("transparency", 1.0); stairs = static_cast(element->getAttribute("stairs")); - if (stairs) - { - if (draw_edges) - { - logger((stderr, "\"stairs\" is not compatible with \"draw_edges\" / colormap\n")); - } - else if (num_bin_edges == 0) /* no bin_edges */ - { - mlist.resize(num_bins * 4); - } - else - { - rectlist.resize(num_bins); - } - } + if (stairs) rect_list.resize(num_bins); } - if (plot_group->hasAttribute("r_lim_min") && plot_group->hasAttribute("r_lim_max")) + if (phi_flip) std::reverse(classes.begin(), classes.end()); + + /* if phi_flip and bin_edges are given --> invert the angles */ + if (phi_flip && num_bin_edges > 0) { - r_lim_vec.push_back(static_cast(plot_group->getAttribute("r_lim_min"))); - r_lim_vec.push_back(static_cast(plot_group->getAttribute("r_lim_max"))); - r_lim = &(r_lim_vec[0]); + std::vector temp1(num_bin_edges), temp2(num_bins); - mlist.resize((num_bins + 1) * 4); - r_min = grm_min(r_lim[0], r_lim[1]); - r_max = grm_max(r_lim[0], r_lim[1]); - if (r_lim[0] > r_lim[1]) + for (i = 0; i < num_bin_edges; i++) { - r_lim[0] = r_min; - r_lim[1] = r_max; + temp1[i] = 2 * M_PI - bin_edges[num_bin_edges - 1 - i]; } - - if (r_max > 1.0) + bin_edges = temp1; + for (i = (int)num_bins - 1; i >= 0; --i) { - r_max = 1.0; - logger((stderr, "The value of \"r_lim_max\" can not exceed 1.0\n")); + temp2[i] = bin_widths[num_bins - 1 - i]; } - if (r_min < 0.0) r_min = 0.0; + bin_widths = temp2; } - if (phiflip) std::reverse(classes.begin(), classes.end()); - - /* if phiflip and bin_edges are given --> invert the angles */ - if (phiflip && num_bin_edges > 0) + // Special colormap case + if (!(element->hasAttribute("x_colormap") && element->hasAttribute("y_colormap"))) { - int u; - std::vector temp(num_bin_edges), temp2(num_bins); - - for (u = 0; u < num_bin_edges; u++) - { - temp[u] = 2 * M_PI - bin_edges[num_bin_edges - 1 - u]; - } - for (u = (int)num_bins - 1; u >= 0; --u) - { - temp2[u] = bin_widths[num_bins - 1 - u]; - } - bin_widths = temp2; - bin_edges = temp; + if (draw_edges) logger((stderr, "\"draw_edges\" can only be used with colormap\n")); + } + else + { + x_colormap = static_cast(element->getAttribute("x_colormap")); + y_colormap = static_cast(element->getAttribute("y_colormap")); } - for (int class_nr = 0; class_nr < classes.size(); ++class_nr) + // Iterate through the classes and create for every bar a polar_bar element + // main loop used for each bar (and arc in stairs, but not the lines in stairs) + for (int class_nr = 0; class_nr < classes.size(); class_nr++) { double count = classes[class_nr]; - if (classes[class_nr] == 0) - { - /* stairs bin_edges / phi_lim */ - if (!rectlist.empty() && phi_lim != nullptr) - rectlist[class_nr] = r_min; - else if (!rectlist.empty()) - rectlist[class_nr] = 0.0; - } - if (str_equals_any(norm, "probability", "cdf")) - { - count /= total_observations; - } - else if (norm == "pdf") + if (y_log) { - if (num_bin_edges == 0) - { - count /= total_observations * bin_width; - } + if (count > 0) + count = log10(count); else - { - count /= (total_observations * bin_widths[class_nr]); - } + continue; } - else if (norm == "countdensity") - { - if (num_bin_edges == 0) - { - count /= bin_width; - } - else - { - count /= bin_widths[class_nr]; - } + + // adjust count according to the given normalization + if (str_equals_any(norm, "probability", "cdf")) + { + count /= total_observations; } - - if (!(element->hasAttribute("x_colormap") && element->hasAttribute("y_colormap"))) + else if (norm == "pdf") { - if (draw_edges) logger((stderr, "\"draw_edges\" can only be used with colormap\n")); + count /= num_bin_edges == 0 ? (total_observations * bin_width) : (total_observations * bin_widths[class_nr]); } - else + else if (norm == "countdensity") { - xcolormap = static_cast(element->getAttribute("x_colormap")); - ycolormap = static_cast(element->getAttribute("y_colormap")); + count /= num_bin_edges == 0 ? bin_width : bin_widths[class_nr]; } - if (!stairs) + if (!stairs) // no stairs uses `polar_bar` logic which is implemented in `processPolarBar` { std::shared_ptr polar_bar; @@ -9614,12 +10730,12 @@ static void processPolarHistogram(const std::shared_ptr &element, { if (bin_width != -1) polar_bar->setAttribute("bin_width", bin_width); if (norm != "count") polar_bar->setAttribute("norm", norm); - if (phiflip) polar_bar->setAttribute("phi_flip", phiflip); + if (phi_flip) polar_bar->setAttribute("phi_flip", phi_flip); if (draw_edges) polar_bar->setAttribute("draw_edges", draw_edges); if (edge_color != 1) polar_bar->setAttribute("line_color_ind", edge_color); if (face_color != 989) polar_bar->setAttribute("color_ind", face_color); - if (xcolormap != -2) polar_bar->setAttribute("x_colormap", xcolormap); - if (ycolormap != -2) polar_bar->setAttribute("y_colormap", ycolormap); + if (x_colormap != -2) polar_bar->setAttribute("x_colormap", x_colormap); + if (y_colormap != -2) polar_bar->setAttribute("y_colormap", y_colormap); if (!bin_widths.empty()) polar_bar->setAttribute("bin_widths", bin_widths[class_nr]); if (!bin_edges.empty()) { @@ -9634,12 +10750,17 @@ static void processPolarHistogram(const std::shared_ptr &element, } } } - else if (!draw_edges && (xcolormap == -2 && ycolormap == -2)) /* stairs without draw_edges (not compatible) */ + else if (!draw_edges && (x_colormap == -2 && y_colormap == -2)) /* stairs without draw_edges (not compatible) */ { + // this is for drawing the arcs in stairs. double r, rect; - std::complex complex1, complex2; + std::complex complex1; const double convert = 180.0 / M_PI; double edge_width = 2.3; /* only for stairs */ + bool draw_inner = true; + double start_angle, end_angle; + std::shared_ptr arc; + double arc_pos = 0.0; global_render->setFillColorInd(element, 1); global_render->setLineColorInd(element, edge_color); @@ -9648,127 +10769,96 @@ static void processPolarHistogram(const std::shared_ptr &element, processFillColorInd(element); processLineWidth(element); - r = pow((count / max), (num_bins * 2)); + /* perform calculations for later usages, this r is used for complex calculations */ + if (keep_radii_axes && ylims) + { + r = pow(count / r_max, num_bins * 2); + if (r > pow(y_lim_max / r_max, num_bins * 2)) r = pow(y_lim_max / r_max, num_bins * 2); + } + else if (ylims) + { + // trim count to [0.0, y_lim_max] + count = grm_max(0.0, grm_min(count, y_lim_max) - y_lim_min); + r = pow((count / (y_lim_max - y_lim_min)), num_bins * 2); + } + else + { + r = pow(count / r_max, num_bins * 2); + } + complex1 = moivre(r, (2 * class_nr), (int)num_bins * 2); - complex2 = moivre(r, (2 * class_nr + 2), ((int)num_bins * 2)); rect = sqrt(pow(real(complex1), 2) + pow(imag(complex1), 2)); - /* no bin_edges */ - if (num_bin_edges == 0) + if (num_bin_edges) { - double arc_pos; - std::shared_ptr arc; - - mlist[class_nr * 4] = real(complex1); - mlist[class_nr * 4 + 1] = imag(complex1); - mlist[class_nr * 4 + 2] = real(complex2); - mlist[class_nr * 4 + 3] = imag(complex2); + start_angle = bin_edges[class_nr] * convert; + end_angle = bin_edges[class_nr + 1] * convert; + } + else + { + start_angle = class_nr * (360.0 / num_bins); + end_angle = (class_nr + 1) * (360.0 / num_bins); + } - if (r_lim != nullptr) + rect_list[class_nr] = rect; + if (ylims) + { + if (keep_radii_axes) { - for (int i = 0; i < 2; ++i) + if (count <= y_lim_min) { - double temporary = - fabs(sqrt(pow(mlist[class_nr * 4 + 2 - i * 2], 2) + pow(mlist[class_nr * 4 + 3 - i * 2], 2))); - if (temporary > r_max) - { - double factor = fabs(r_max / temporary); - mlist[class_nr * 4 + 2 - i * 2] *= factor; - mlist[class_nr * 4 + 3 - i * 2] *= factor; - } + rect_list[class_nr] = y_lim_min / r_max; + draw_inner = false; } + else if (rect > r_max) // Todo: r_max or 1.0 as previous? + rect_list[class_nr] = y_lim_max; - if (rect > r_min) - { - if (del != del_values::update_without_default && del != del_values::update_with_default) - { - arc = global_render->createDrawArc( - -grm_min(rect, r_max), grm_min(rect, r_max), -grm_min(rect, r_max), grm_min(rect, r_max), - class_nr * (360.0 / num_bins), (class_nr + 1) * 360.0 / num_bins); - arc->setAttribute("_child_id", child_id++); - element->append(arc); - } - else - { - arc = element->querySelectors("draw_arc[_child_id=" + std::to_string(child_id++) + "]"); - if (arc != nullptr) - global_render->createDrawArc(-grm_min(rect, r_max), grm_min(rect, r_max), - -grm_min(rect, r_max), grm_min(rect, r_max), - class_nr * (360.0 / num_bins), - (class_nr + 1) * 360.0 / num_bins, arc); - } - - arc_pos = r_min; - } - } - else /* no r_lim */ - { - arc_pos = rect; - } - if (del != del_values::update_without_default && del != del_values::update_with_default) - { - arc = - global_render->createDrawArc(-arc_pos, arc_pos, -arc_pos, arc_pos, class_nr * (360.0 / num_bins), - (class_nr + 1) * (360.0 / num_bins)); - arc->setAttribute("_child_id", child_id++); - element->append(arc); + auto complex_min = moivre(pow(y_lim_min / r_max, num_bins * 2), (2 * class_nr), (int)num_bins * 2); + arc_pos = sqrt(pow(real(complex_min), 2) + pow(imag(complex_min), 2)); + if (count <= y_lim_min) arc_pos = 0.0; } else { - arc = element->querySelectors("draw_arc[_child_id=" + std::to_string(child_id++) + "]"); - if (arc != nullptr) - global_render->createDrawArc(-arc_pos, arc_pos, -arc_pos, arc_pos, class_nr * (360.0 / num_bins), - (class_nr + 1) * (360.0 / num_bins), arc); + draw_inner = false; // without keep_radii_axes draw_inner is not needed + + // y_lim_min is already subtracted from count + if (count < 0) + rect_list[class_nr] = 0.0; + else if (count >= y_lim_max - y_lim_min) + rect_list[class_nr] = 1.0; // 1.0 equals y_lim_max (when no keep_radii_axes is set) } - } - else /* with bin_edges */ - { - /* r_lim and bin_edges */ - std::shared_ptr arc; - double arc_pos; - if (r_lim != nullptr) + // this is the outer arc + if ((count > 0 && !keep_radii_axes) || (count > y_lim_min && keep_radii_axes)) { - if (rect < r_min) - rectlist[class_nr] = r_min; - else if (rect > r_max) - rectlist[class_nr] = r_max; + double min = grm_min(rect, r_max); // Todo: r_max or 1.0 as previous? + if (del != del_values::update_without_default && del != del_values::update_with_default) + { + arc = global_render->createDrawArc(-min, min, -min, min, start_angle, end_angle); + arc->setAttribute("_child_id", child_id++); + element->append(arc); + } else - rectlist[class_nr] = rect; - - if (rect > r_min) { - if (del != del_values::update_without_default && del != del_values::update_with_default) - { - arc = global_render->createDrawArc( - -grm_min(rect, r_max), grm_min(rect, r_max), -grm_min(rect, r_max), grm_min(rect, r_max), - bin_edges[class_nr] * convert, bin_edges[class_nr + 1] * convert); - arc->setAttribute("_child_id", child_id++); - element->append(arc); - } - else - { - arc = element->querySelectors("draw_arc[_child_id=" + std::to_string(child_id++) + "]"); - if (arc != nullptr) - global_render->createDrawArc(-grm_min(rect, r_max), grm_min(rect, r_max), - -grm_min(rect, r_max), grm_min(rect, r_max), - bin_edges[class_nr] * convert, - bin_edges[class_nr + 1] * convert, arc); - } - - arc_pos = r_min; + arc = element->querySelectors("draw_arc[_child_id=" + std::to_string(child_id++) + "]"); + if (arc != nullptr) + global_render->createDrawArc(-min, min, -min, min, start_angle, end_angle, arc); } } - else /* no r_lim */ - { - rectlist[class_nr] = rect; - if (class_nr == num_bin_edges - 1) break; - arc_pos = rect; - } + } + else + { + if (class_nr == classes.size()) break; + arc_pos = rect; + } + + // these are the inner arcs with ylim (keep_radii_axes only) and the normal_arcs without ylims, only if it's + // higher than y_lim_min + if (draw_inner) + { if (del != del_values::update_without_default && del != del_values::update_with_default) { - arc = global_render->createDrawArc(-arc_pos, arc_pos, -arc_pos, arc_pos, - bin_edges[class_nr] * convert, bin_edges[class_nr + 1] * convert); + arc = global_render->createDrawArc(-arc_pos, arc_pos, -arc_pos, arc_pos, start_angle, end_angle); arc->setAttribute("_child_id", child_id++); element->append(arc); } @@ -9776,74 +10866,49 @@ static void processPolarHistogram(const std::shared_ptr &element, { arc = element->querySelectors("draw_arc[_child_id=" + std::to_string(child_id++) + "]"); if (arc != nullptr) - global_render->createDrawArc(-arc_pos, arc_pos, -arc_pos, arc_pos, bin_edges[class_nr] * convert, - bin_edges[class_nr + 1] * convert, arc); + global_render->createDrawArc(-arc_pos, arc_pos, -arc_pos, arc_pos, start_angle, end_angle, arc); } } } } /* end of classes for loop */ - if (stairs && !draw_edges && (xcolormap == -2 && ycolormap == -2)) + // this is for drawing the stair lines + if (stairs && !draw_edges && (x_colormap == -2 && y_colormap == -2)) { std::shared_ptr line; double line_x[2], line_y[2]; + double start_x = 0.0, start_y = 0.0; // start_x/y is the coordinate for minimum radius (y_lim_min) + std::vector angles_vec; - /* stairs without bin_edges, r_lim */ - if (!mlist.empty() && r_lim == nullptr && rectlist.empty()) + if (num_bin_edges != 0) { - for (int s = 0; s < num_bins * 4; s += 2) - { - if (s > 2 && s % 4 == 0) - { - line_x[0] = mlist[s]; - line_x[1] = mlist[s - 2]; - line_y[0] = mlist[s + 1]; - line_y[1] = mlist[s - 1]; - - if (del != del_values::update_without_default && del != del_values::update_with_default) - { - line = global_render->createPolyline(line_x[0], line_x[1], line_y[0], line_y[1]); - line->setAttribute("_child_id", child_id++); - element->append(line); - } - else - { - line = element->querySelectors("polyline[_child_id=" + std::to_string(child_id++) + "]"); - if (line != nullptr) - global_render->createPolyline(line_x[0], line_x[1], line_y[0], line_y[1], 0, 0.0, 0, line); - } - } - } - line_x[0] = mlist[0]; - line_x[1] = mlist[(num_bins - 1) * 4 + 2]; - line_y[0] = mlist[1]; - line_y[1] = mlist[(num_bins - 1) * 4 + 3]; + start_x = grm_max(rect_list[0] * cos(bin_edges[0]), r_min * cos(bin_edges[0])); + start_y = grm_max(rect_list[0] * sin(bin_edges[0]), r_min * sin(bin_edges[0])); + angles_vec = bin_edges; } - else if (!mlist.empty() && r_lim != nullptr && rectlist.empty()) /* stairs without bin_edges with r_lim*/ + else { - double rect1, rect2; + start_x = grm_max(rect_list[0], ylims ? (y_lim_min / y_lim_max) : (r_min / r_max)); + start_y = 0.0; + linspace(0.0, 2 * M_PI, (int)classes.size() + 1, angles_vec); + } - for (int x = 0; x < num_bins; ++x) - { - rect1 = sqrt(pow(mlist[x * 4], 2) + pow(mlist[x * 4 + 1], 2)); - rect2 = sqrt(pow(mlist[(x - 1) * 4 + 2], 2) + pow(mlist[(x - 1) * 4 + 3], 2)); + auto start_angle = angles_vec[0]; + auto end_angle = angles_vec[angles_vec.size() - 1]; + for (i = 0; i < angles_vec.size() - 1; i++) + { + line_x[0] = start_x; + line_x[1] = rect_list[i] * cos(angles_vec[i]); + line_y[0] = start_y; + line_y[1] = rect_list[i] * sin(angles_vec[i]); - if (rect1 < r_min && rect2 < r_min) continue; - if (rect1 < r_min) - { - mlist[4 * x] = r_min * cos(2 * M_PI / num_bins * x); - mlist[4 * x + 1] = r_min * sin(2 * M_PI / num_bins * x); - } - else if (rect2 < r_min) - { - mlist[(x - 1) * 4 + 2] = r_min * cos(2 * M_PI / num_bins * x); - mlist[(x - 1) * 4 + 3] = r_min * sin(2 * M_PI / num_bins * x); - } - line_x[0] = mlist[x * 4]; - line_x[1] = mlist[(x - 1) * 4 + 2]; - line_y[0] = mlist[x * 4 + 1]; - line_y[1] = mlist[(x - 1) * 4 + 3]; + start_x = rect_list[i] * cos(angles_vec[i + 1]); + start_y = rect_list[i] * sin(angles_vec[i + 1]); + if ((!ylims && !(start_angle == 0.0 && end_angle > 1.96 * M_PI) || i > 0) || + ((!phi_flip && (!((start_angle > 0.0 && start_angle < 0.001) && end_angle > 1.96 * M_PI) || i > 0)) || + ((start_angle > 1.96 * M_PI && !(end_angle > 0.0 && end_angle < 0.001)) || i > 0))) + { if (del != del_values::update_without_default && del != del_values::update_with_default) { line = global_render->createPolyline(line_x[0], line_x[1], line_y[0], line_y[1]); @@ -9857,129 +10922,43 @@ static void processPolarHistogram(const std::shared_ptr &element, global_render->createPolyline(line_x[0], line_x[1], line_y[0], line_y[1], 0, 0.0, 0, line); } } - line_x[0] = mlist[(num_bins - 1) * 4 + 2] = grm_max(mlist[(num_bins - 1) * 4 + 2], r_min * cos(0)); - line_y[0] = mlist[(num_bins - 1) * 4 + 3] = grm_max(mlist[(num_bins - 1) * 4 + 3], r_min * sin(0)); - line_x[1] = mlist[0] = grm_max(mlist[0], r_min * cos(0)); - line_y[1] = mlist[1] = grm_max(mlist[1], r_min * sin(0)); } - else if (!rectlist.empty() && r_lim == nullptr) /* stairs with bin_edges without r_lim */ - { - double startx = 0.0, starty = 0.0; - - for (int x = 0; x < num_bin_edges - 1; ++x) - { - line_x[0] = startx; - line_x[1] = rectlist[x] * cos(bin_edges[x]); - line_y[0] = starty; - line_y[1] = rectlist[x] * sin(bin_edges[x]); - - startx = rectlist[x] * cos(bin_edges[x + 1]); - starty = rectlist[x] * sin(bin_edges[x + 1]); - if (!(bin_edges[0] == 0.0 && bin_edges[num_bin_edges - 1] > 1.96 * M_PI) || x > 0) - { - if (del != del_values::update_without_default && del != del_values::update_with_default) - { - line = global_render->createPolyline(line_x[0], line_x[1], line_y[0], line_y[1]); - line->setAttribute("_child_id", child_id++); - element->append(line); - } - else - { - line = element->querySelectors("polyline[_child_id=" + std::to_string(child_id++) + "]"); - if (line != nullptr) - global_render->createPolyline(line_x[0], line_x[1], line_y[0], line_y[1], 0, 0.0, 0, line); - } - } - } + // draw a line when it is not a full circle + if (ylims && !(start_angle == 0.0 && end_angle > 1.96 * M_PI)) + { + line_x[0] = y_lim_min / y_lim_max * cos(start_angle); + line_x[1] = rect_list[0] * cos(start_angle); + line_y[0] = y_lim_min / y_lim_max * sin(start_angle); + line_y[1] = rect_list[0] * sin(start_angle); - if (bin_edges[0] == 0.0 && bin_edges[num_bin_edges - 1] > 1.96 * M_PI) + if (del != del_values::update_without_default && del != del_values::update_with_default) { - line_x[0] = rectlist[0] * cos(bin_edges[0]); - line_x[1] = startx; - line_y[0] = rectlist[0] * sin(bin_edges[0]); - line_y[1] = starty; + line = global_render->createPolyline(line_x[0], line_x[1], line_y[0], line_y[1]); + line->setAttribute("_child_id", child_id++); + element->append(line); } else { - line_x[0] = rectlist[num_bin_edges - 2] * cos(bin_edges[num_bin_edges - 1]); - line_x[1] = 0.0; - line_y[0] = rectlist[num_bin_edges - 2] * sin(bin_edges[num_bin_edges - 1]); - line_y[1] = 0.0; + line = element->querySelectors("polyline[_child_id=" + std::to_string(child_id++) + "]"); + if (line != nullptr) + global_render->createPolyline(line_x[0], line_x[1], line_y[0], line_y[1], 0, 0.0, 0, line); } } - else if (!rectlist.empty() && r_lim != nullptr) /* stairs with bin_edges and r_lim */ - { - double startx = grm_max(rectlist[0] * cos(bin_edges[0]), r_min * cos(bin_edges[0])); - double starty = grm_max(rectlist[0] * sin(bin_edges[0]), r_min * sin(bin_edges[0])); - - for (int x = 0; x < num_bin_edges - 1; ++x) - { - line_x[0] = startx; - line_x[1] = rectlist[x] * cos(bin_edges[x]); - line_y[0] = starty; - line_y[1] = rectlist[x] * sin(bin_edges[x]); - - startx = rectlist[x] * cos(bin_edges[x + 1]); - starty = rectlist[x] * sin(bin_edges[x + 1]); - - if ((!phiflip && - (!((bin_edges[0] > 0.0 && bin_edges[0] < 0.001) && bin_edges[num_bin_edges - 1] > 1.96 * M_PI) || - x > 0)) || - ((bin_edges[0] > 1.96 * M_PI && - !(bin_edges[num_bin_edges - 1] > 0.0 && bin_edges[num_bin_edges - 1] < 0.001)) || - x > 0)) - { - if (del != del_values::update_without_default && del != del_values::update_with_default) - { - line = global_render->createPolyline(line_x[0], line_x[1], line_y[0], line_y[1]); - line->setAttribute("_child_id", child_id++); - element->append(line); - } - else - { - line = element->querySelectors("polyline[_child_id=" + std::to_string(child_id++) + "]"); - if (line != nullptr) - global_render->createPolyline(line_x[0], line_x[1], line_y[0], line_y[1], 0, 0.0, 0, line); - } - } - } - - if (!(bin_edges[0] == 0.0 && bin_edges[num_bin_edges - 1] > 1.96 * M_PI)) - { - line_x[0] = r_min * cos(bin_edges[0]); - line_x[1] = rectlist[0] * cos(bin_edges[0]); - line_y[0] = r_min * sin(bin_edges[0]); - line_y[1] = rectlist[0] * sin(bin_edges[0]); - - if (del != del_values::update_without_default && del != del_values::update_with_default) - { - line = global_render->createPolyline(line_x[0], line_x[1], line_y[0], line_y[1]); - line->setAttribute("_child_id", child_id++); - element->append(line); - } - else - { - line = element->querySelectors("polyline[_child_id=" + std::to_string(child_id++) + "]"); - if (line != nullptr) - global_render->createPolyline(line_x[0], line_x[1], line_y[0], line_y[1], 0, 0.0, 0, line); - } - } - if (bin_edges[0] == 0.0 && bin_edges[num_bin_edges - 1] > 1.96 * M_PI) - { - line_x[0] = rectlist[0] * cos(bin_edges[0]); - line_x[1] = rectlist[num_bin_edges - 2] * cos(bin_edges[num_bin_edges - 1]); - line_y[0] = rectlist[0] * sin(bin_edges[0]); - line_y[1] = rectlist[num_bin_edges - 2] * sin(bin_edges[num_bin_edges - 1]); - } - else - { - line_x[0] = rectlist[num_bin_edges - 2] * cos(bin_edges[num_bin_edges - 1]); - line_x[1] = r_min * cos(bin_edges[num_bin_edges - 1]); - line_y[0] = rectlist[num_bin_edges - 2] * sin(bin_edges[num_bin_edges - 1]); - line_y[1] = r_min * sin(bin_edges[num_bin_edges - 1]); - } + if (start_angle == 0.0 && end_angle > 1.96 * M_PI) + { + line_x[0] = rect_list[0]; + line_x[1] = ylims ? rect_list[angles_vec.size() - 2] * cos(end_angle) : start_x; + line_y[0] = 0.0; + line_y[1] = ylims ? rect_list[angles_vec.size() - 2] * sin(end_angle) : start_y; + } + else + { + line_x[0] = rect_list[angles_vec.size() - 2] * cos(end_angle); + line_x[1] = ylims ? y_lim_min / y_lim_max * cos(end_angle) : 0.0; + line_y[0] = rect_list[angles_vec.size() - 2] * sin(end_angle); + line_y[1] = ylims ? y_lim_min / y_lim_max * sin(end_angle) : 0.0; } if (del != del_values::update_without_default && del != del_values::update_with_default) @@ -9999,52 +10978,56 @@ static void processPolarHistogram(const std::shared_ptr &element, static void processPolarBar(const std::shared_ptr &element, const std::shared_ptr &context) { - unsigned int resample; - double *r_lim = nullptr; double r, rect; - std::complex complex1, complex2; - std::vector angles, bin_edges; - std::vector colormap; + double y_lim_min, y_lim_max; + std::complex complex1; const double convert = 180.0 / M_PI; - std::vector lineardata, bin_counts; - std::vector f1, f2, arc_2_x, arc_2_y; - std::vector phi_vec, r_lim_vec; - std::complex r_min_complex1, r_min_complex2; + std::vector f1, f2, arc_2_x, arc_2_y, phi_vec, bin_edges; int child_id = 0; - int xcolormap = -2, ycolormap = -2; - double count, bin_width = -1.0, bin_widths; - double r_min = 0.0, r_max = 1.0, max; + int x_colormap = -2, y_colormap = -2, edge_color = 1, face_color = 989; + double count, bin_width = -1.0, r_max; int num_bins, num_bin_edges = 0, class_nr; std::string norm = "count", str; - bool phiflip = false, draw_edges = false; - int edge_color = 1, face_color = 989; - std::vector mlist = {0.0, 0.0, 0.0, 0.0}; - std::shared_ptr plot_elem = element->parentElement(); - getPlotParent(plot_elem); + bool phi_flip = false, draw_edges = false, keep_radii_axes = false, y_lim = false, is_colormap = false, y_log = false; del_values del = del_values::update_without_default; + std::shared_ptr plot_parent = element; + getPlotParent(plot_parent); /* clear old polar-histogram children */ del = del_values(static_cast(element->getAttribute("_delete_children"))); clearOldChildren(&del, element); + // class_nr is used for the position of the bar in the histogram class_nr = static_cast(element->getAttribute("class_nr")); + // count is already converted by normalization count = static_cast(element->getAttribute("count")); + if (plot_parent->hasAttribute("y_log")) y_log = static_cast(plot_parent->getAttribute("y_log")); + if (element->hasAttribute("bin_width")) bin_width = static_cast(element->getAttribute("bin_width")); if (element->hasAttribute("norm")) norm = static_cast(element->getAttribute("norm")); - if (element->hasAttribute("phi_flip")) phiflip = static_cast(element->getAttribute("phi_flip")); + if (element->hasAttribute("phi_flip")) phi_flip = static_cast(element->getAttribute("phi_flip")); if (element->hasAttribute("draw_edges")) draw_edges = static_cast(element->getAttribute("draw_edges")); if (element->hasAttribute("line_color_ind")) edge_color = static_cast(element->getAttribute("line_color_ind")); if (element->hasAttribute("color_ind")) face_color = static_cast(element->getAttribute("color_ind")); - if (element->hasAttribute("x_colormap")) xcolormap = static_cast(element->getAttribute("x_colormap")); - if (element->hasAttribute("y_colormap")) ycolormap = static_cast(element->getAttribute("y_colormap")); + + if (element->hasAttribute("x_colormap")) + { + x_colormap = static_cast(element->getAttribute("x_colormap")); + is_colormap = true; + } + if (element->hasAttribute("y_colormap")) + { + y_colormap = static_cast(element->getAttribute("y_colormap")); + is_colormap = true; + } + if (element->hasAttribute("bin_edges")) { auto bin_edges_key = static_cast(element->getAttribute("bin_edges")); bin_edges = GRM::get>((*context)[bin_edges_key]); num_bin_edges = (int)bin_edges.size(); } - if (element->hasAttribute("bin_widths")) bin_widths = static_cast(element->getAttribute("bin_widths")); num_bins = static_cast(element->parentElement()->getAttribute("num_bins")); if (element->parentElement()->hasAttribute("bin_widths")) @@ -10052,41 +11035,37 @@ static void processPolarBar(const std::shared_ptr &element, const auto bin_widths_key = static_cast(element->parentElement()->getAttribute("bin_widths")); auto bin_widths_vec = GRM::get>((*context)[bin_widths_key]); num_bins = (int)bin_widths_vec.size(); + bin_width = bin_widths_vec[class_nr]; } + r_max = static_cast(plot_parent->querySelectors("central_region")->getAttribute("r_max")); + if (y_log) r_max = log10(r_max); - if (plot_elem->hasAttribute("r_lim_min") && plot_elem->hasAttribute("r_lim_max")) + // no ylims -> max = y_lim_max; with ylims -> max = max_count of series + if (plot_parent->hasAttribute("y_lim_min") && plot_parent->hasAttribute("y_lim_max")) { - r_lim_vec.push_back(static_cast(plot_elem->getAttribute("r_lim_min"))); - r_lim_vec.push_back(static_cast(plot_elem->getAttribute("r_lim_max"))); - r_lim = &(r_lim_vec[0]); + y_lim = true; + y_lim_min = static_cast(plot_parent->getAttribute("y_lim_min")); + y_lim_max = static_cast(plot_parent->getAttribute("y_lim_max")); - r_min = grm_min(r_lim[0], r_lim[1]); - r_max = grm_max(r_lim[0], r_lim[1]); - if (r_lim[0] > r_lim[1]) + if (y_log) { - r_lim[0] = r_min; - r_lim[1] = r_max; + y_lim_min = log10(y_lim_min); + y_lim_max = log10(y_lim_max); } - if (r_max > 1.0) - { - r_max = 1.0; - logger((stderr, "The value of \"r_lim_max\" can not exceed 1.0\n")); - } - if (r_min < 0.0) r_min = 0.0; + if (plot_parent->hasAttribute("keep_radii_axes")) + keep_radii_axes = static_cast(plot_parent->getAttribute("keep_radii_axes")); } - for (const auto &child : plot_elem->children()) + else { - if (child->localName() == "central_region") - { - max = static_cast(child->getAttribute("r_max")); - break; - } + y_lim_min = 0.0; + y_lim_max = r_max; } - if (element->hasAttribute("x_colormap") && element->hasAttribute("y_colormap")) + // creates an image for draw_image + if (is_colormap) { - if (-1 > xcolormap || xcolormap > 47 || ycolormap < -1 || ycolormap > 47) + if (-1 > x_colormap || x_colormap > 47 || y_colormap < -1 || y_colormap > 47) { logger((stderr, "The value for keyword \"colormap\" must contain two integer between -1 and 47\n")); } @@ -10094,30 +11073,36 @@ static void processPolarBar(const std::shared_ptr &element, const { std::shared_ptr draw_image; const int colormap_size = 500, image_size = 2000; - double radius, angle, max_radius; + /* Todo: maybe use dynamic image_size when using interactions or maybe calculate a smaller rectangle in image + only one bar per rectangle -> no image_size * image_size iterations or maybe don't iterate through + image_size * image_size matrix instead calculate the coordinates and iterate through these coordinates + somehow like in python */ + double radius, angle, max_radius, count_radius; + double start_angle, end_angle, y_axis_max; + double y_lim_min_radius, y_lim_max_radius; int total = 0; - double norm_factor = 1; - auto id = static_cast(global_root->getAttribute("_id")); + double norm_factor = 1, original_count = count; + std::vector linear_data, colormap; + auto id = static_cast(global_root->getAttribute("_id")); global_root->setAttribute("_id", id + 1); str = std::to_string(id); - lineardata.resize(image_size * image_size); - bin_counts.resize(num_bins); - - createColormap(xcolormap, ycolormap, colormap_size, colormap); + linear_data.resize(image_size * image_size); + createColormap(x_colormap, y_colormap, colormap_size, colormap); if (num_bin_edges == 0) { - angles.resize(num_bins + 1); - linspace(0.0, M_PI * 2, (int)num_bins + 1, angles); + start_angle = M_PI * 2 / ((int)num_bins) * class_nr; + end_angle = M_PI * 2 / ((int)num_bins) * (class_nr + 1); } else { - angles = bin_edges; + start_angle = bin_edges[class_nr]; + end_angle = bin_edges[class_nr + 1]; } - max_radius = image_size / 2; + max_radius = image_size / 2.0; total = static_cast(element->getAttribute("total")); if (str_equals_any(norm, "probability", "cdf")) @@ -10127,344 +11112,218 @@ static void processPolarBar(const std::shared_ptr &element, const else if (num_bin_edges == 0 && norm == "countdensity") norm_factor = bin_width; - if (r_lim != nullptr) - { - r_min *= max_radius; - r_max *= max_radius; - } - else - { - r_min = 0.0; - r_max = max_radius; - } - - for (int y = 0; y < image_size; y++) - { - for (int x = 0; x < image_size; x++) - { - radius = sqrt(pow(x - max_radius, 2) + pow(y - max_radius, 2)); - angle = atan2(y - max_radius, x - max_radius); - - if (angle < 0) angle += M_PI * 2; - if (!phiflip) angle = 2 * M_PI - angle; - - if (angle > angles[class_nr] && angle <= angles[class_nr + 1]) - { - if (norm == "pdf" && num_bin_edges > 0) - norm_factor = total * bin_widths; - else if (norm == "countdensity" && num_bin_edges > 0) - norm_factor = bin_widths; - - if ((grm_round(radius * 100) / 100) <= - (grm_round((count * 1.0 / norm_factor / max * max_radius) * 100) / 100) && - radius <= r_max && radius > r_min) - { - lineardata[y * image_size + x] = colormap - [(int)(radius / (max_radius * pow(2, 0.5)) * (colormap_size - 1)) * colormap_size + - grm_max(grm_min((int)(angle / (2 * M_PI) * colormap_size), colormap_size - 1), 0)]; - } - - } /* end angle check */ - } /* end x loop */ - } /* end y loop */ - if (r_lim != nullptr) - { - r_min = r_lim[0]; - r_max = r_lim[1]; - } - - /* save resample method and reset because it isn't restored with gr_restorestate */ - if (del != del_values::update_without_default && del != del_values::update_with_default) - { - draw_image = global_render->createDrawImage(-1.0, 1.0, 1.0, -1.0, image_size, image_size, "data" + str, - lineardata, 0); - draw_image->setAttribute("_child_id", child_id++); - element->append(draw_image); - } - else - { - draw_image = element->querySelectors("draw_image[_child_id=" + std::to_string(child_id++) + "]"); - if (draw_image != nullptr) - global_render->createDrawImage(-1.0, 1.0, 1.0, -1.0, image_size, image_size, "data" + str, lineardata, - 0, nullptr, draw_image); - } - gr_inqresamplemethod(&resample); - if (draw_image != nullptr) global_render->setResampleMethod(draw_image, static_cast(0x2020202)); - lineardata.clear(); - colormap.clear(); - } - } - - /* perform calculations for later usages */ - r = pow((count / max), num_bins * 2); - complex1 = moivre(r, 2 * class_nr, (int)num_bins * 2); - - rect = sqrt(pow(real(complex1), 2) + pow(imag(complex1), 2)); - - if (r_lim != nullptr) - { - complex2 = moivre(r, 2 * class_nr + 2, (int)num_bins * 2); - - mlist[0] = real(complex1); - mlist[1] = imag(complex1); - mlist[2] = real(complex2); - mlist[3] = imag(complex2); - - r_min_complex1 = moivre(pow((r_min), (num_bins * 2)), (class_nr * 2), (int)num_bins * 2); - r_min_complex2 = moivre(pow((r_min), (num_bins * 2)), (class_nr * 2 + 2), (int)num_bins * 2); - - /* check if the segment is higher than rmax? */ - for (int i = 0; i < 2; ++i) - { - double temporary = fabs(sqrt(pow(mlist[2 - i * 2], 2) + pow(mlist[3 - i * 2], 2))); - if (temporary > r_max) + if (!keep_radii_axes) { - double factor = fabs(r_max / temporary); - mlist[2 - i * 2] *= factor; - mlist[3 - i * 2] *= factor; + y_axis_max = (y_lim_max - y_lim_min); + if (count > y_lim_max) count = y_lim_max; + count -= y_lim_min; } - } - r = count / max; - if (r > r_max) r = r_max; - } - - /* no bin_edges */ - if (num_bin_edges == 0) - { - if (r_lim != nullptr) - { - int i, num_angle; - double start_angle, end_angle; - std::shared_ptr area; - auto id = static_cast(global_root->getAttribute("_id")); - - if (r > r_min) - { - global_root->setAttribute("_id", id + 1); - str = std::to_string(id); - - start_angle = class_nr * (360.0 / num_bins) / convert; - end_angle = (class_nr + 1) * (360.0 / num_bins) / convert; - - /* determine number of angles for arc approximations */ - num_angle = (int)((end_angle - start_angle) / (0.2 / convert)); - - phi_vec.resize(num_angle); - linspace(start_angle, end_angle, num_angle, phi_vec); - - /* 4 because of the 4 corner coordinates and 2 * num_angle for the arc approximations, top and bottom */ - f1.resize(4 + 2 * num_angle); - /* line_1_x[0] and [1] */ - f1[0] = real(r_min_complex1); - f1[1] = mlist[0]; - /* arc_1_x */ - listcomprehension(r, cos, phi_vec, num_angle, 2, f1); - /* reversed line_2_x [0] and [1] */ - f1[2 + num_angle + 1] = real(r_min_complex2); - f1[2 + num_angle] = mlist[2]; - /* reversed arc_2_x */ - listcomprehension(r_min, cos, phi_vec, num_angle, 0, arc_2_x); - for (i = 0; i < num_angle; ++i) - { - f1[2 + num_angle + 2 + i] = arc_2_x[num_angle - 1 - i]; - } - arc_2_x.clear(); - - f2.resize(4 + 2 * num_angle); - /* line_1_y[0] and [1] */ - f2[0] = imag(r_min_complex1); - f2[1] = mlist[1]; - /* arc_1_y */ - listcomprehension(r, sin, phi_vec, num_angle, 2, f2); - /* reversed line_2_y [0] and [1] */ - f2[2 + num_angle + 1] = imag(r_min_complex2); - f2[2 + num_angle] = mlist[3]; - /* reversed arc_2_y */ - listcomprehension(r_min, sin, phi_vec, num_angle, 0, arc_2_y); - for (i = 0; i < num_angle; ++i) - { - f2[2 + num_angle + 2 + i] = arc_2_y[num_angle - 1 - i]; - } - arc_2_y.clear(); - - if (!draw_edges) - { - /* with r_lim gr_fillarc cant be used because it will always draw from the origin instead use - * gr_fillarea and approximate line segment with calculations from above */ - if (del != del_values::update_without_default && del != del_values::update_with_default) - { - area = global_render->createFillArea("x" + str, f1, "y" + str, f2); - area->setAttribute("_child_id", child_id++); - element->append(area); - } - else - { - area = element->querySelectors("fill_area[_child_id=" + std::to_string(child_id++) + "]"); - if (area != nullptr) - global_render->createFillArea("x" + str, f1, "y" + str, f2, nullptr, 0, 0, -1, area); - } - - if (area != nullptr) - { - global_render->setFillColorInd(area, face_color); - global_render->setFillIntStyle(area, 1); - } - } - - /* draw_area more likely */ - if (del != del_values::update_without_default && del != del_values::update_with_default) - { - area = global_render->createFillArea("x" + str, f1, "y" + str, f2); - area->setAttribute("_child_id", child_id++); - element->append(area); - } - else - { - area = element->querySelectors("fill_area[_child_id=" + std::to_string(child_id++) + "]"); - if (area != nullptr) - global_render->createFillArea("x" + str, f1, "y" + str, f2, nullptr, 0, 0, -1, area); - } - if (area != nullptr) - { - global_render->setFillColorInd(area, edge_color); - global_render->setFillIntStyle(area, 0); - area->setAttribute("z_index", 2); - } - - /* clean up vectors for next iteration */ - phi_vec.clear(); - f1.clear(); - f2.clear(); + else + { + y_axis_max = r_max; // r_max = true y axis maximum + y_lim_min_radius = y_lim_min / r_max * max_radius; + y_lim_max_radius = grm_min(y_lim_max, r_max) / r_max * max_radius; } - } /* end r_lim condition */ - else /* no r_lim */ - { - std::shared_ptr arc, draw_arc; - if (!draw_edges) + if (norm == "pdf" && num_bin_edges > 0) + norm_factor = total * bin_width; + else if (norm == "countdensity" && num_bin_edges > 0) + norm_factor = bin_width; + + // calculate the radius of the bar with height count + count_radius = (grm_round((count * 1.0 / norm_factor / y_axis_max * max_radius) * 100) / 100); + + // go through every point in the image and check if it's inside a bar + for (int y = 0; y < image_size; y++) { - if (del != del_values::update_without_default && del != del_values::update_with_default) - { - arc = global_render->createFillArc(-rect, rect, -rect, rect, class_nr * (360.0 / num_bins), - (class_nr + 1) * (360.0 / num_bins)); - arc->setAttribute("_child_id", child_id++); - element->append(arc); - } - else + for (int x = 0; x < image_size; x++) { - arc = element->querySelectors("fill_arc[_child_id=" + std::to_string(child_id++) + "]"); - if (arc != nullptr) - global_render->createFillArc(-rect, rect, -rect, rect, class_nr * (360.0 / num_bins), - (class_nr + 1) * (360.0 / num_bins), 0, 0, -1, arc); - } + radius = sqrt(pow(x - max_radius, 2) + pow(y - max_radius, 2)); + radius = grm_round(radius * 100) / 100; + angle = atan2(y - max_radius, x - max_radius); - if (arc != nullptr) - { - global_render->setFillIntStyle(arc, 1); - global_render->setFillColorInd(arc, face_color); + if (angle < 0) angle += M_PI * 2; + if (!phi_flip) angle = 2 * M_PI - angle; + + if (angle > start_angle && angle <= end_angle && + ((keep_radii_axes && radius <= count_radius && radius <= y_lim_max_radius && + radius > y_lim_min_radius) || + ((grm_round(radius * 100) / 100) <= count_radius && radius <= max_radius && count > 0.0))) + { + linear_data[y * image_size + x] = + colormap[(int)(radius / (max_radius * sqrt(2)) * (colormap_size - 1)) * colormap_size + + grm_max(grm_min((int)(angle / (2 * M_PI) * colormap_size), colormap_size - 1), 0)]; + } } } + /* save resample method and reset because it isn't restored with gr_restorestate */ if (del != del_values::update_without_default && del != del_values::update_with_default) { - draw_arc = global_render->createFillArc(-rect, rect, -rect, rect, class_nr * (360.0 / num_bins), - (class_nr + 1) * (360.0 / num_bins)); - draw_arc->setAttribute("_child_id", child_id++); - element->append(draw_arc); + draw_image = global_render->createDrawImage(-1.0, 1.0, 1.0, -1.0, image_size, image_size, "data" + str, + linear_data, 0); + draw_image->setAttribute("_child_id", child_id++); + element->append(draw_image); } else { - draw_arc = element->querySelectors("fill_arc[_child_id=" + std::to_string(child_id++) + "]"); - if (draw_arc != nullptr) - global_render->createFillArc(-rect, rect, -rect, rect, class_nr * (360.0 / num_bins), - (class_nr + 1) * (360.0 / num_bins), 0, 0, -1, draw_arc); + draw_image = element->querySelectors("draw_image[_child_id=" + std::to_string(child_id++) + "]"); + if (draw_image != nullptr) + global_render->createDrawImage(-1.0, 1.0, 1.0, -1.0, image_size, image_size, "data" + str, linear_data, + 0, nullptr, draw_image); + } + if (draw_image != nullptr) global_render->setResampleMethod(draw_image, static_cast(0x2020202)); + linear_data.clear(); + colormap.clear(); + count = original_count; + } + } // end of colormaps + + if (!keep_radii_axes) count = grm_max(grm_min(count, y_lim_max) - y_lim_min, 0.0); // trim count to [0.0, y_lim_max] + + /* perform calculations for later usages, this r is used for complex calculations */ + if (keep_radii_axes) + r = grm_min(pow((count / r_max), num_bins * 2), pow(y_lim_max / r_max, num_bins * 2)); + else + r = pow((count / (y_lim_max - y_lim_min)), num_bins * 2); + + complex1 = moivre(r, 2 * class_nr, (int)num_bins * 2); + + // draw_arc rectangle + rect = sqrt(pow(real(complex1), 2) + pow(imag(complex1), 2)); + + if (y_lim) + { + // this r is used directly for the radii of each draw_arc + if (keep_radii_axes) + { + r = grm_min(count / r_max, y_lim_max / r_max); + } + else + { + r = count / (y_lim_max - y_lim_min); + if (r > y_lim_max) r = 1.0; + } + } + + // if keep_radii_axes is given, then arcs can not be easily drawn (because of the lower arc [donut shaped]), so + // additional calculations are needed for arcs and lines + if (!keep_radii_axes) + { + std::shared_ptr arc, draw_arc; + double start_angle, end_angle; + + if (num_bin_edges != 0.0) + { + start_angle = bin_edges[0] * convert; + end_angle = bin_edges[1] * convert; + } + else + { + start_angle = class_nr * (360.0 / num_bins); + end_angle = (class_nr + 1) * (360.0 / num_bins); + } + if (!draw_edges && !is_colormap) + { + if (del != del_values::update_without_default && del != del_values::update_with_default) + { + arc = global_render->createFillArc(-rect, rect, -rect, rect, start_angle, end_angle); + arc->setAttribute("_child_id", child_id++); + element->append(arc); } - if (draw_arc != nullptr) + else + { + arc = element->querySelectors("fill_arc[_child_id=" + std::to_string(child_id++) + "]"); + if (arc != nullptr) + global_render->createFillArc(-rect, rect, -rect, rect, start_angle, end_angle, 0, 0, -1, arc); + } + + if (arc != nullptr) { - global_render->setFillIntStyle(draw_arc, 0); - global_render->setFillColorInd(draw_arc, edge_color); - draw_arc->setAttribute("z_index", 2); + global_render->setFillIntStyle(arc, 1); + global_render->setFillColorInd(arc, face_color); } } + + if (del != del_values::update_without_default && del != del_values::update_with_default) + { + draw_arc = global_render->createFillArc(-rect, rect, -rect, rect, start_angle, end_angle); + draw_arc->setAttribute("_child_id", child_id++); + element->append(draw_arc); + } + else + { + draw_arc = element->querySelectors("fill_arc[_child_id=" + std::to_string(child_id++) + "]"); + if (draw_arc != nullptr) + global_render->createFillArc(-rect, rect, -rect, rect, start_angle, end_angle, 0, 0, -1, draw_arc); + } + if (draw_arc != nullptr) + { + global_render->setFillIntStyle(draw_arc, 0); + global_render->setFillColorInd(draw_arc, edge_color); + draw_arc->setAttribute("z_index", 2); + } } - else /* bin_egdes */ + else /* keep_radii_axes is given so extra calculations are needed */ { - if (r_lim != nullptr) + int num_angle; + double start_angle, end_angle; + std::shared_ptr area; + auto id = static_cast(global_root->getAttribute("_id")); + + if (count > y_lim_min && keep_radii_axes) // check if original count (count + y_lim_min) is larger than y_lim_min { - double start_angle, end_angle; - int num_angle, i; - std::shared_ptr area; - int id = (int)global_root->getAttribute("_id"); + global_root->setAttribute("_id", id + 1); + str = std::to_string(id); - if (r > r_min) + if (num_bin_edges != 0.0) { - global_root->setAttribute("_id", id + 1); - str = std::to_string(id); - start_angle = bin_edges[0]; end_angle = bin_edges[1]; + } + else + { + start_angle = class_nr * (360.0 / num_bins) / convert; + end_angle = (class_nr + 1) * (360.0 / num_bins) / convert; + } - num_angle = (int)((end_angle - start_angle) / (0.2 / convert)); - phi_vec.resize(num_angle); - linspace(start_angle, end_angle, num_angle, phi_vec); - - f1.resize(4 + 2 * num_angle); - /* line_1_x[0] and [1] */ - f1[0] = cos(bin_edges[0]) * r_min; - f1[1] = grm_min(rect, r_max) * cos(bin_edges[0]); - /* arc_1_x */ - listcomprehension(r, cos, phi_vec, num_angle, 2, f1); - /* reversed line_2_x [0] and [1] */ - f1[2 + num_angle + 1] = cos(bin_edges[1]) * r_min; - f1[2 + num_angle] = grm_min(rect, r_max) * cos(bin_edges[1]); - /* reversed arc_2_x */ - listcomprehension(r_min, cos, phi_vec, num_angle, 0, arc_2_x); - for (i = 0; i < num_angle; ++i) - { - f1[2 + num_angle + 2 + i] = arc_2_x[num_angle - 1 - i]; - } - arc_2_x.clear(); - - f2.resize(4 + 2 * num_angle); - /* line_1_y[0] and [1] */ - f2[0] = r_min * sin(bin_edges[0]); - f2[1] = grm_min(rect, r_max) * sin(bin_edges[0]); - /* arc_1_y */ - listcomprehension(r, sin, phi_vec, num_angle, 2, f2); - /* reversed line_2_y [0] and [1] */ - f2[2 + num_angle + 1] = r_min * sin(bin_edges[1]); - f2[2 + num_angle] = grm_min(rect, r_max) * sin(bin_edges[1]); - /* reversed arc_2_y */ - listcomprehension(r_min, sin, phi_vec, num_angle, 0, arc_2_y); - for (i = 0; i < num_angle; ++i) - { - f2[2 + num_angle + 2 + i] = arc_2_y[num_angle - 1 - i]; - } - arc_2_y.clear(); + // determine number of angles for arc approximations + num_angle = (int)((end_angle - start_angle) / (0.2 / convert)); + phi_vec.resize(num_angle); + linspace(start_angle, end_angle, num_angle, phi_vec); - if (!draw_edges) - { - if (del != del_values::update_without_default && del != del_values::update_with_default) - { - area = global_render->createFillArea("x" + str, f1, "y" + str, f2); - area->setAttribute("_child_id", child_id++); - element->append(area); - } - else - { - area = element->querySelectors("fill_area[_child_id=" + std::to_string(child_id++) + "]"); - if (area != nullptr) - global_render->createFillArea("x" + str, f1, "y" + str, f2, nullptr, 0, 0, -1, area); - } + /* 4 because of the 4 corner coordinates and 2 * num_angle for the arc approximations, top and bottom */ + f1.resize(4 + 2 * num_angle); + f2.resize(4 + 2 * num_angle); - if (area != nullptr) - { - global_render->setFillColorInd(area, face_color); - global_render->setFillIntStyle(area, 1); - } - } + /* line_1_x/y[0] and [1] */ + f1[0] = cos(start_angle) * y_lim_min / r_max; + f1[1] = rect * cos(start_angle); + f2[0] = y_lim_min / r_max * sin(start_angle); + f2[1] = rect * sin(start_angle); + + /* arc_1_x and arc_1_y */ + listcomprehension(r, cos, phi_vec, num_angle, 2, f1); + listcomprehension(r, sin, phi_vec, num_angle, 2, f2); + + /* reversed line_2_x/y[0] and [1] */ + f1[2 + num_angle + 1] = cos(end_angle) * y_lim_min / r_max; + f1[2 + num_angle] = rect * cos(end_angle); + f2[2 + num_angle + 1] = y_lim_min / r_max * sin(end_angle); + f2[2 + num_angle] = rect * sin(end_angle); + + /* reversed arc_2_x and arc_2_y */ + listcomprehension(keep_radii_axes ? (y_lim_min / r_max) : 0.0, cos, phi_vec, num_angle, 0, arc_2_x); + listcomprehension(keep_radii_axes ? (y_lim_min / r_max) : 0.0, sin, phi_vec, num_angle, 0, arc_2_y); + + for (int i = 0; i < num_angle; i++) + { + f1[2 + num_angle + 2 + i] = arc_2_x[num_angle - 1 - i]; + f2[2 + num_angle + 2 + i] = arc_2_y[num_angle - 1 - i]; + } - /* draw_area more likely */ + if (!draw_edges) + { if (del != del_values::update_without_default && del != del_values::update_with_default) { area = global_render->createFillArea("x" + str, f1, "y" + str, f2); @@ -10477,67 +11336,31 @@ static void processPolarBar(const std::shared_ptr &element, const if (area != nullptr) global_render->createFillArea("x" + str, f1, "y" + str, f2, nullptr, 0, 0, -1, area); } - if (area != nullptr) - { - global_render->setFillColorInd(area, edge_color); - global_render->setFillIntStyle(area, 0); - area->setAttribute("z_index", 2); - } - - /* clean up vectors for next iteration */ - phi_vec.clear(); - f1.clear(); - f2.clear(); - } - } - else /* no r_lim */ - { - std::shared_ptr arc, draw_arc; - - if (!draw_edges) - { - if (del != del_values::update_without_default && del != del_values::update_with_default) - { - arc = global_render->createFillArc(-rect, rect, -rect, rect, bin_edges[0] * convert, - bin_edges[1] * convert); - arc->setAttribute("_child_id", child_id++); - element->append(arc); - } - else - { - arc = element->querySelectors("fill_arc[_child_id=" + std::to_string(child_id++) + "]"); - if (arc != nullptr) - global_render->createFillArc(-rect, rect, -rect, rect, bin_edges[0] * convert, - bin_edges[1] * convert, 0, 0, -1, arc); - } - if (arc != nullptr) + if (area != nullptr) { - global_render->setFillIntStyle(arc, 1); - global_render->setFillColorInd(arc, face_color); + global_render->setFillColorInd(area, face_color); + global_render->setFillIntStyle(area, 1); } } - /* draw_arc */ + // draw_area more likely if (del != del_values::update_without_default && del != del_values::update_with_default) { - draw_arc = global_render->createFillArc(-rect, rect, -rect, rect, bin_edges[0] * convert, - bin_edges[1] * convert); - draw_arc->setAttribute("_child_id", child_id++); - element->append(draw_arc); + area = global_render->createFillArea("x" + str, f1, "y" + str, f2); + area->setAttribute("_child_id", child_id++); + element->append(area); } else { - draw_arc = element->querySelectors("fill_arc[_child_id=" + std::to_string(child_id++) + "]"); - if (draw_arc != nullptr) - global_render->createFillArc(-rect, rect, -rect, rect, bin_edges[0] * convert, bin_edges[1] * convert, - 0, 0, -1, draw_arc); + area = element->querySelectors("fill_area[_child_id=" + std::to_string(child_id++) + "]"); + if (area != nullptr) global_render->createFillArea("x" + str, f1, "y" + str, f2, nullptr, 0, 0, -1, area); } - if (draw_arc != nullptr) + if (area != nullptr) { - global_render->setFillIntStyle(draw_arc, 0); - global_render->setFillColorInd(draw_arc, edge_color); - draw_arc->setAttribute("z_index", 2); + global_render->setFillColorInd(area, edge_color); + global_render->setFillIntStyle(area, 0); + area->setAttribute("z_index", 2); } } } @@ -10704,14 +11527,9 @@ static void processScatter(const std::shared_ptr &element, const s } } - if (!marker_sizes_vec.empty()) - { - global_render->setMarkerSize(element, "marker_sizes" + str, marker_sizes_vec); - } + if (!marker_sizes_vec.empty()) global_render->setMarkerSize(element, "marker_sizes" + str, marker_sizes_vec); if (!marker_color_inds_vec.empty()) - { - global_render->setMarkerColorInd(element, "marker_color_indices" + str, marker_color_inds_vec); - } + global_render->setMarkerColorInd(element, "marker_color_indices" + str, marker_color_inds_vec); } else { @@ -10805,14 +11623,9 @@ static void processScatter3(const std::shared_ptr &element, const for (i = 0; i < x_length; i++) { - if (i < c_length) - { - c_index = 1000 + (int)(255.0 * (c_vec[i] - c_min) / (c_max - c_min) + 0.5); - } - else - { - c_index = 989; - } + c_index = 989; + if (i < c_length) c_index = 1000 + (int)(255.0 * (c_vec[i] - c_min) / (c_max - c_min) + 0.5); + marker_c_vec.push_back((int)c_index); } } @@ -10856,11 +11669,11 @@ static void processStairs(const std::shared_ptr &element, const st * \param[in] element The GRM::Element that contains the attributes and data keys * \param[in] context The GRM::Context that contains the actual data */ - std::string kind, orientation = PLOT_DEFAULT_ORIENTATION, line_spec = SERIES_DEFAULT_SPEC; + std::string orientation = PLOT_DEFAULT_ORIENTATION, line_spec = SERIES_DEFAULT_SPEC; bool is_vertical; unsigned int x_length, y_length, mask, i; std::vector x_vec, y_vec; - std::shared_ptr element_context = element, line; + std::shared_ptr element_context = element, line, marker; del_values del = del_values::update_without_default; int child_id = 0; @@ -10877,7 +11690,6 @@ static void processStairs(const std::shared_ptr &element, const st x_length = x_vec.size(); y_length = y_vec.size(); - kind = static_cast(element->getAttribute("kind")); if (element->hasAttribute("orientation")) { orientation = static_cast(element->getAttribute("orientation")); @@ -10906,9 +11718,7 @@ static void processStairs(const std::shared_ptr &element, const st if (element->parentElement()->parentElement()->hasAttribute("marginal_heatmap_side_plot")) { - double y_max = 0; int x_offset = 0, y_offset = 0; - std::vector z_vec; if (element_context->parentElement()->hasAttribute("x_log") && static_cast(element_context->parentElement()->getAttribute("x_log"))) @@ -10927,9 +11737,6 @@ static void processStairs(const std::shared_ptr &element, const st } } - auto z = static_cast(element_context->getAttribute("z")); - z_vec = GRM::get>((*context)[z]); - std::vector xi_vec((is_vertical ? y_length - y_offset : x_length - x_offset)); (*context)["xi" + str] = xi_vec; element->setAttribute("xi", "xi" + str); @@ -10947,6 +11754,8 @@ static void processStairs(const std::shared_ptr &element, const st if (int_equals_any((int)mask, 5, 0, 1, 3, 4, 5)) { std::string where = PLOT_DEFAULT_STEP_WHERE; + int current_line_color_ind; + gr_inqlinecolorind(¤t_line_color_ind); if (element->hasAttribute("step_where")) { where = static_cast(element->getAttribute("step_where")); @@ -10973,10 +11782,7 @@ static void processStairs(const std::shared_ptr &element, const st } std::vector line_x = x_step_boundaries, line_y = y_step_values; - if (is_vertical) - { - line_x = y_step_values, line_y = x_step_boundaries; - } + if (is_vertical) line_x = y_step_values, line_y = x_step_boundaries; if (del != del_values::update_without_default && del != del_values::update_with_default) { line = global_render->createPolyline("x" + str, line_x, "y" + str, line_y); @@ -11007,10 +11813,7 @@ static void processStairs(const std::shared_ptr &element, const st y_step_values[2 * x_length - 2] = y_vec[x_length - 1]; std::vector line_x = x_step_boundaries, line_y = y_step_values; - if (is_vertical) - { - line_x = y_step_values, line_y = x_step_boundaries; - } + if (is_vertical) line_x = y_step_values, line_y = x_step_boundaries; if (del != del_values::update_without_default && del != del_values::update_with_default) { line = global_render->createPolyline("x" + str, line_x, "y" + str, line_y); @@ -11040,10 +11843,7 @@ static void processStairs(const std::shared_ptr &element, const st } std::vector line_x = x_step_boundaries, line_y = y_step_values; - if (is_vertical) - { - line_x = y_step_values, line_y = x_step_boundaries; - } + if (is_vertical) line_x = y_step_values, line_y = x_step_boundaries; if (del != del_values::update_without_default && del != del_values::update_with_default) { line = global_render->createPolyline("x" + str, line_x, "y" + str, line_y); @@ -11057,25 +11857,43 @@ static void processStairs(const std::shared_ptr &element, const st global_render->createPolyline("x" + str, line_x, "y" + str, line_y, nullptr, 0, 0.0, 0, line); } } + if (line != nullptr) line->setAttribute("line_color_ind", current_line_color_ind); } if (mask & 2) { - std::vector line_x = x_vec, line_y = y_vec; + std::vector marker_x = x_vec, marker_y = y_vec; + int current_marker_color_ind; + gr_inqmarkercolorind(¤t_marker_color_ind); if (is_vertical) { - line_x = y_vec, line_y = x_vec; + marker_x = y_vec, marker_y = x_vec; } if (del != del_values::update_without_default && del != del_values::update_with_default) { - line = global_render->createPolyline("x" + str, line_x, "y" + str, line_y); - line->setAttribute("_child_id", child_id++); - element->append(line); + marker = global_render->createPolymarker("x" + str, marker_x, "y" + str, marker_y); + marker->setAttribute("_child_id", child_id++); + element->append(marker); } else { - line = element->querySelectors("polyline[_child_id=" + std::to_string(child_id++) + "]"); - if (line != nullptr) - global_render->createPolyline("x" + str, line_x, "y" + str, line_y, nullptr, 0, 0.0, 0, line); + marker = element->querySelectors("polymarker[_child_id=" + std::to_string(child_id++) + "]"); + if (marker != nullptr) + global_render->createPolymarker("x" + str, marker_x, "y" + str, marker_y, nullptr, 0, 0.0, 0, marker); + } + if (marker != nullptr) + { + marker->setAttribute("marker_color_ind", current_marker_color_ind); + marker->setAttribute("z_index", 2); + + if (element->hasAttribute("marker_type")) + { + marker->setAttribute("marker_type", static_cast(element->getAttribute("marker_type"))); + } + else + { + marker->setAttribute("marker_type", *previous_line_marker_type++); + if (*previous_line_marker_type == INT_MAX) previous_line_marker_type = plot_scatter_markertypes; + } } } } @@ -11092,14 +11910,14 @@ static void processStem(const std::shared_ptr &element, const std: double stem_x[2], stem_y[2] = {0.0}; std::string orientation = PLOT_DEFAULT_ORIENTATION, line_spec = SERIES_DEFAULT_SPEC; bool is_vertical; - double x_min, x_max, y_min, y_max; unsigned int x_length, y_length; unsigned int i; std::vector x_vec, y_vec; del_values del = del_values::update_without_default; int child_id = 0; - std::shared_ptr line, marker; + std::shared_ptr line, marker, coordinate_system; double old_stem_y0; + int mask, current_line_color_ind; if (!element->hasAttribute("x")) throw NotFoundError("Stem series is missing required attribute x-data.\n"); auto x = static_cast(element->getAttribute("x")); @@ -11121,6 +11939,8 @@ static void processStem(const std::shared_ptr &element, const std: { element->setAttribute("line_spec", line_spec); } + const char *spec_char = line_spec.c_str(); + mask = gr_uselinespec((char *)spec_char); is_vertical = orientation == "vertical"; x_vec = GRM::get>((*context)[x]); @@ -11129,7 +11949,15 @@ static void processStem(const std::shared_ptr &element, const std: y_length = y_vec.size(); if (x_length != y_length) throw std::length_error("For stem series x- and y-data must have the same size.\n"); - if (element->hasAttribute("y_range_min")) stem_y[0] = static_cast(element->getAttribute("y_range_min")); + coordinate_system = element->parentElement()->querySelectors("coordinate_system"); + if (coordinate_system != nullptr && coordinate_system->hasAttribute("y_line")) + { + auto y_line = coordinate_system->querySelectors("polyline[name=\"y_line\"]"); + if (y_line != nullptr) + { + stem_y[0] = static_cast(y_line->getAttribute(orientation == "horizontal" ? "y1" : "x1")); + } + } /* clear all old polylines and -marker */ del = del_values(static_cast(element->getAttribute("_delete_children"))); @@ -11149,17 +11977,22 @@ static void processStem(const std::shared_ptr &element, const std: stem_x[0] = stem_y[0], stem_x[1] = stem_y[1]; stem_y[0] = tmp1, stem_y[1] = tmp2; } - if (del != del_values::update_without_default && del != del_values::update_with_default) - { - line = global_render->createPolyline(stem_x[0], stem_x[1], stem_y[0], stem_y[1]); - line->setAttribute("_child_id", child_id++); - element->append(line); - } - else + if (int_equals_any(mask, 5, 0, 1, 3, 4, 5)) { - line = element->querySelectors("polyline[_child_id=" + std::to_string(child_id++) + "]"); - if (line != nullptr) - global_render->createPolyline(stem_x[0], stem_x[1], stem_y[0], stem_y[1], 0, 0.0, 0, line); + gr_inqlinecolorind(¤t_line_color_ind); + if (del != del_values::update_without_default && del != del_values::update_with_default) + { + line = global_render->createPolyline(stem_x[0], stem_x[1], stem_y[0], stem_y[1]); + line->setAttribute("_child_id", child_id++); + element->append(line); + } + else + { + line = element->querySelectors("polyline[_child_id=" + std::to_string(child_id++) + "]"); + if (line != nullptr) + global_render->createPolyline(stem_x[0], stem_x[1], stem_y[0], stem_y[1], 0, 0.0, 0, line); + } + if (line != nullptr) line->setAttribute("line_color_ind", current_line_color_ind); } } @@ -11168,10 +12001,7 @@ static void processStem(const std::shared_ptr &element, const std: auto str = std::to_string(id); std::vector marker_x = x_vec, marker_y = y_vec; - if (is_vertical) - { - marker_x = y_vec, marker_y = x_vec; - } + if (is_vertical) marker_x = y_vec, marker_y = x_vec; if (del != del_values::update_without_default && del != del_values::update_with_default) { marker = global_render->createPolymarker("x" + str, marker_x, "y" + str, marker_y, nullptr, @@ -11186,6 +12016,11 @@ static void processStem(const std::shared_ptr &element, const std: global_render->createPolymarker("x" + str, marker_x, "y" + str, marker_y, nullptr, GKS_K_MARKERTYPE_SOLID_CIRCLE, 0.0, 0, marker); } + if (marker != nullptr) + { + marker->setAttribute("z_index", 2); + marker->setAttribute("marker_color_ind", current_line_color_ind); + } } static void processShade(const std::shared_ptr &element, const std::shared_ptr &context) @@ -11449,10 +12284,7 @@ static void processLine(const std::shared_ptr &element, const std: auto str = std::to_string(id); std::vector line_x = x_vec, line_y = y_vec; - if (orientation == "vertical") - { - line_x = y_vec, line_y = x_vec; - } + if (orientation == "vertical") line_x = y_vec, line_y = x_vec; if (del != del_values::update_without_default && del != del_values::update_with_default) { line = global_render->createPolyline("x" + str, line_x, "y" + str, line_y); @@ -11477,10 +12309,7 @@ static void processLine(const std::shared_ptr &element, const std: auto str = std::to_string(id); std::vector marker_x = x_vec, marker_y = y_vec; - if (orientation == "vertical") - { - marker_x = y_vec, marker_y = x_vec; - } + if (orientation == "vertical") marker_x = y_vec, marker_y = x_vec; if (del != del_values::update_without_default && del != del_values::update_with_default) { marker = global_render->createPolymarker("x" + str, marker_x, "y" + str, marker_y); @@ -11506,10 +12335,7 @@ static void processLine(const std::shared_ptr &element, const std: else { marker->setAttribute("marker_type", *previous_line_marker_type++); - if (*previous_line_marker_type == INT_MAX) - { - previous_line_marker_type = plot_scatter_markertypes; - } + if (*previous_line_marker_type == INT_MAX) previous_line_marker_type = plot_scatter_markertypes; } } global_root->setAttribute("_id", ++id); @@ -11533,7 +12359,6 @@ static void processMarginalHeatmapPlot(const std::shared_ptr &elem */ double c_max; - int flip, options; int x_ind = PLOT_DEFAULT_MARGINAL_INDEX, y_ind = PLOT_DEFAULT_MARGINAL_INDEX; unsigned int i, j, k; std::string algorithm = PLOT_DEFAULT_MARGINAL_ALGORITHM, marginal_heatmap_kind = PLOT_DEFAULT_MARGINAL_KIND; @@ -11705,10 +12530,7 @@ static void processMarginalHeatmapPlot(const std::shared_ptr &elem bins[(k == 0) ? i : j] = grm_max(bins[(k == 0) ? i : j], value); } } - if (k == 0) - { - bin_max = grm_max(bin_max, bins[i]); - } + if (k == 0) bin_max = grm_max(bin_max, bins[i]); } if (k == 1) { @@ -11926,7 +12748,7 @@ static int set_next_color(const std::string &key, gr_color_type_t color_type, &saved_color[2]); } - current_array_index %= color_array_length; + current_array_index %= (int)color_array_length; if (!color_indices.empty()) { @@ -11941,26 +12763,12 @@ static int set_next_color(const std::string &key, gr_color_type_t color_type, color_rgb_values[current_array_index + 1], color_rgb_values[current_array_index + 2]); } - if (color_type & GR_COLOR_LINE) - { - global_render->setLineColorInd(element, color_index); - } - if (color_type & GR_COLOR_MARKER) - { - global_render->setMarkerColorInd(element, color_index); - } - if (color_type & GR_COLOR_FILL) - { - global_render->setFillColorInd(element, color_index); - } - if (color_type & GR_COLOR_TEXT) - { - global_render->setTextColorInd(element, color_index); - } - if (color_type & GR_COLOR_BORDER) - { - global_render->setBorderColorInd(element, color_index); - } + if (color_type & GR_COLOR_LINE) global_render->setLineColorInd(element, color_index); + if (color_type & GR_COLOR_MARKER) global_render->setMarkerColorInd(element, color_index); + if (color_type & GR_COLOR_FILL) global_render->setFillColorInd(element, color_index); + if (color_type & GR_COLOR_TEXT) global_render->setTextColorInd(element, color_index); + if (color_type & GR_COLOR_BORDER) global_render->setBorderColorInd(element, color_index); + return color_index; } @@ -12029,8 +12837,7 @@ static void processPie(const std::shared_ptr &element, const std:: */ unsigned int x_length; int color_index; - double start_angle, middle_angle, end_angle; - double text_pos[2]; + double start_angle, end_angle; char text[80]; std::string title; unsigned int i; @@ -12082,10 +12889,7 @@ static void processPie(const std::shared_ptr &element, const std:: } start_angle = end_angle; - if (start_angle < 0) - { - start_angle += 360.0; - } + if (start_angle < 0) start_angle += 360.0; } set_next_color("", GR_COLOR_RESET, element, context); processFillColorInd(element); @@ -12285,22 +13089,22 @@ static void processImshow(const std::shared_ptr &element, const st del = del_values(static_cast(element->getAttribute("_delete_children"))); clearOldChildren(&del, element); - std::shared_ptr cellarray; + std::shared_ptr cell_array; if (del != del_values::update_without_default && del != del_values::update_with_default) { - cellarray = global_render->createCellArray(x_min, x_max, y_min, y_max, cols, rows, 1, 1, cols, rows, img_data_key, - std::nullopt); - cellarray->setAttribute("_child_id", child_id++); - element->append(cellarray); + cell_array = global_render->createCellArray(x_min, x_max, y_min, y_max, cols, rows, 1, 1, cols, rows, + img_data_key, std::nullopt); + cell_array->setAttribute("_child_id", child_id++); + element->append(cell_array); } else { - cellarray = element->querySelectors("cellarray[_child_id=" + std::to_string(child_id++) + "]"); - if (cellarray != nullptr) + cell_array = element->querySelectors("cell_array[_child_id=" + std::to_string(child_id++) + "]"); + if (cell_array != nullptr) global_render->createCellArray(x_min, x_max, y_min, y_max, cols, rows, 1, 1, cols, rows, img_data_key, - std::nullopt, nullptr, cellarray); + std::nullopt, nullptr, cell_array); } - if (cellarray != nullptr) cellarray->setAttribute("name", "imshow"); + if (cell_array != nullptr) cell_array->setAttribute("name", "imshow"); } static void processText(const std::shared_ptr &element, const std::shared_ptr &context) @@ -12385,8 +13189,8 @@ static void processTextRegion(const std::shared_ptr &element, const std::shared_ptr &context) { double viewport[4], char_height; - double x, y; - std::string kind, location, text; + double x = 0.0, y = 0.0; + std::string location, text; bool is_title; del_values del = del_values::update_without_default; std::shared_ptr plot_parent = element->parentElement(), side_region = element->parentElement(), @@ -12404,7 +13208,6 @@ static void processTextRegion(const std::shared_ptr &element, viewport[1] = static_cast(element->getAttribute("viewport_x_max")); viewport[2] = static_cast(element->getAttribute("viewport_y_min")); viewport[3] = static_cast(element->getAttribute("viewport_y_max")); - kind = static_cast(plot_parent->getAttribute("kind")); location = static_cast(side_region->getAttribute("location")); is_title = side_region->hasAttribute("text_is_title") && static_cast(side_region->getAttribute("text_is_title")); text = static_cast(side_region->getAttribute("text_content")); @@ -12449,10 +13252,16 @@ static void processTextRegion(const std::shared_ptr &element, { if (location == "left" || location == "top") global_render->setTextAlign(text_elem, GKS_K_TEXT_HALIGN_CENTER, GKS_K_TEXT_VALIGN_TOP); - if (location == "bottom" || location == "bottom") + else if (location == "right" || location == "bottom") global_render->setTextAlign(text_elem, GKS_K_TEXT_HALIGN_CENTER, GKS_K_TEXT_VALIGN_BOTTOM); - if (location == "top" && is_title) text_elem->setAttribute("z_index", 2); - if (location == "left" || location == "right") global_render->setCharUp(text_elem, -1, 0); + if (location == "top" && is_title) + text_elem->setAttribute("z_index", 2); + else + text_elem->setAttribute("z_index", 0); + if (location == "left" || location == "right") + global_render->setCharUp(text_elem, -1, 0); + else + global_render->setCharUp(text_elem, 0, 1); } } @@ -12460,19 +13269,23 @@ static void tickLabelAdjustment(const std::shared_ptr &tick_group, { double char_height; double available_width, available_height; - double x, y; - double null, x_left = 0, x_right = 1; // todo: change x_left and x_right + double x, y, y_org, width; double window[4]; - int scientific_format = 0; + int scientific_format = 2; std::shared_ptr text_elem, plot_parent = tick_group; char new_label[256]; - int cur_start = 0, scale = 0; - bool x_flip, y_flip; + int cur_start = 0, scale = 0, cur_child_count = 0, child_id_org = child_id - 1, i = 0; + bool x_flip, y_flip, text_is_empty_or_number = true; + int pixel_width, pixel_height; + double metric_width, metric_height; + double aspect_ratio_ws_metric; + GRM::Render::getFigureSize(&pixel_width, &pixel_height, &metric_width, &metric_height); + aspect_ratio_ws_metric = metric_width / metric_height; getPlotParent(plot_parent); gr_inqcharheight(&char_height); + auto text = static_cast(tick_group->getAttribute("tick_label")); - auto width = static_cast(tick_group->getAttribute("width")); auto axis_type = static_cast(tick_group->parentElement()->getAttribute("axis_type")); auto value = static_cast(tick_group->getAttribute("value")); auto label_pos = static_cast(tick_group->parentElement()->getAttribute("label_pos")); @@ -12491,25 +13304,38 @@ static void tickLabelAdjustment(const std::shared_ptr &tick_group, scale = static_cast(tick_group->parentElement()->getAttribute("scale")); if (plot_parent->hasAttribute("x_flip")) x_flip = static_cast(plot_parent->getAttribute("x_flip")); if (plot_parent->hasAttribute("y_flip")) y_flip = static_cast(plot_parent->getAttribute("y_flip")); + if (tick_group->parentElement()->hasAttribute("scientific_format")) + scientific_format = static_cast(tick_group->parentElement()->getAttribute("scientific_format")); + if (tick_group->hasAttribute("scientific_format")) + scientific_format = static_cast(tick_group->getAttribute("scientific_format")); - gr_wctondc(&x_left, &null); - gr_wctondc(&x_right, &null); - - if (text.empty()) return; + if (text.empty() && del != del_values::update_without_default && del != del_values::update_with_default) return; if (axis_type == "x") { - available_height = 0.8; // Todo: change this number - available_width = x_right - x_left; + available_height = 2.0; // Todo: change this number respecting the other objects + available_width = 1.0; // Todo: change this number respecting the other label x = value; y = label_pos; } else if (axis_type == "y") { - available_height = x_right - x_left; - available_width = 0.8; // Todo: change this number + available_height = 3.0; // Todo: change this number respecting the other label + available_width = 1.0; // Todo: change this number respecting the other objects x = label_pos; y = value; } + if (aspect_ratio_ws_metric > 1) + available_width *= 1.0 / (aspect_ratio_ws_metric); + else + available_width *= aspect_ratio_ws_metric; + gr_wctondc(&x, &y); + y_org = y; + + // get number of text children to figure out if children must be added or removed + for (const auto &child : tick_group->children()) + { + if (child->localName() == "text" && child->hasAttribute("_child_id")) cur_child_count += 1; + } if (is_number(text)) { @@ -12517,34 +13343,35 @@ static void tickLabelAdjustment(const std::shared_ptr &tick_group, { char text_c[256]; format_reference_t reference = {1, 1}; - int sc_format = 2; const char minus[] = {(char)0xe2, (char)0x88, (char)0x92, '\0'}; // gr minus sign auto em_dash = std::string(minus); size_t start_pos = 0; - if (tick_group->parentElement()->hasAttribute("scientific_format")) - sc_format = static_cast(tick_group->parentElement()->getAttribute("scientific_format")); - gr_setscientificformat(sc_format); + gr_setscientificformat(scientific_format); - if (starts_with(text, em_dash)) - { - start_pos = em_dash.size(); - } + if (starts_with(text, em_dash)) start_pos = em_dash.size(); auto without_minus = text.substr(start_pos); snprintf(text_c, 256, "%s", without_minus.c_str()); text = gr_ftoa(text_c, atof(without_minus.c_str()), &reference); if (start_pos != 0) text = em_dash + text; - scientific_format = sc_format; } } else { - if (width > available_width) + double tbx[4], tby[4]; + char text_c[256]; + snprintf(text_c, 256, "%s", text.c_str()); + gr_inqtext(x, y, text_c, tbx, tby); + gr_wctondc(&tbx[0], &tby[0]); + gr_wctondc(&tbx[1], &tby[1]); + width = tbx[1] - tbx[0]; + tick_group->setAttribute("width", width); + + if (width / char_height > available_width) { int breakpoint_positions[128]; - int cur_num_breakpoints = 0, i; - double tbx[4], tby[4]; + int cur_num_breakpoints = 0; const char *label = text.c_str(); for (i = 0; i == 0 || label[i - 1] != '\0'; ++i) { @@ -12561,7 +13388,7 @@ static void tickLabelAdjustment(const std::shared_ptr &tick_group, /* add possible breakpoint */ breakpoint_positions[cur_num_breakpoints++] = i; - if (width > available_width) + if (width / char_height > available_width) { /* part is too big but doesn't have a breakpoint in it */ if (cur_num_breakpoints == 1) @@ -12574,9 +13401,10 @@ static void tickLabelAdjustment(const std::shared_ptr &tick_group, new_label[breakpoint_positions[cur_num_breakpoints - 2]] = '\0'; } - if ((del != del_values::update_without_default && del != del_values::update_with_default)) + if ((del != del_values::update_without_default && del != del_values::update_with_default) || + cur_child_count + child_id_org < child_id) { - text_elem = global_render->createText(x, y, new_label + cur_start); + text_elem = global_render->createText(x, y, new_label + cur_start, CoordinateSpace::NDC); tick_group->append(text_elem); text_elem->setAttribute("_child_id", child_id++); } @@ -12586,6 +13414,38 @@ static void tickLabelAdjustment(const std::shared_ptr &tick_group, if (text_elem != nullptr) global_render->createText(x, y, new_label + cur_start, CoordinateSpace::NDC, text_elem); } + if (text_elem != nullptr) + { + if (axis_type == "x") + { + text_elem->setAttribute("text_align_horizontal", GKS_K_TEXT_HALIGN_CENTER); + if (pos <= 0.5 * (window[2] + window[3]) || + ((scale & GR_OPTION_FLIP_Y || y_flip) && pos > 0.5 * (window[2] + window[3]))) + { + text_elem->setAttribute("text_align_vertical", GKS_K_TEXT_VALIGN_TOP); + } + else + { + text_elem->setAttribute("text_align_vertical", GKS_K_TEXT_VALIGN_BOTTOM); + } + } + else if (axis_type == "y") + { + text_elem->setAttribute("text_align_vertical", GKS_K_TEXT_VALIGN_HALF); + if ((pos <= 0.5 * (window[0] + window[1]) && !(scale & GR_OPTION_FLIP_X || x_flip)) || + ((scale & GR_OPTION_FLIP_X || x_flip) && pos > 0.5 * (window[0] + window[1]) && + tick_group->parentElement()->parentElement()->localName() != "colorbar")) + { + text_elem->setAttribute("text_align_horizontal", GKS_K_TEXT_HALIGN_RIGHT); + } + else + { + text_elem->setAttribute("text_align_horizontal", GKS_K_TEXT_HALIGN_LEFT); + } + } + + text_elem->setAttribute("scientific_format", scientific_format); + } if (cur_num_breakpoints == 1) { @@ -12598,7 +13458,10 @@ static void tickLabelAdjustment(const std::shared_ptr &tick_group, breakpoint_positions[0] = breakpoint_positions[cur_num_breakpoints - 1]; cur_num_breakpoints = 1; } - y -= char_height * 1.5; + y -= 1.1 * char_height; + + // if the available height is passed the rest of the label won't get displayed + if ((y_org - y) / char_height > available_height) break; } } else @@ -12610,21 +13473,28 @@ static void tickLabelAdjustment(const std::shared_ptr &tick_group, new_label[i] = '\0'; text = new_label + cur_start; + if (text.empty() && (del != del_values::update_without_default && del != del_values::update_with_default)) + del = del_values::update_without_default; } + if (i >= cur_start && text != " " && text != "\0" && !text.empty() && cur_child_count + child_id_org < child_id) + text_is_empty_or_number = false; + if (i < cur_start && !text_is_empty_or_number) child_id_org += 1; } - if (del != del_values::update_without_default && del != del_values::update_with_default) + if ((del != del_values::update_without_default && del != del_values::update_with_default) || !text_is_empty_or_number) { - text_elem = global_render->createText(x, y, text, CoordinateSpace::WC); + text_elem = global_render->createText(x, y, text, CoordinateSpace::NDC); text_elem->setAttribute("_child_id", child_id); tick_group->append(text_elem); } else { text_elem = tick_group->querySelectors("text[_child_id=" + std::to_string(child_id) + "]"); - if (text_elem != nullptr) global_render->createText(x, y, text, CoordinateSpace::WC, text_elem); + if (text_elem != nullptr) global_render->createText(x, y, text, CoordinateSpace::NDC, text_elem); } - if (text_elem != nullptr && del != del_values::update_without_default) + // Todo: Maybe special case for colorbar so that the adjustment is depending on the location and not on the pos + if ((text_elem != nullptr && del != del_values::update_without_default) || !text_is_empty_or_number || + (text_elem != nullptr && tick_group->parentElement()->parentElement()->localName() == "colorbar")) { text_elem->setAttribute("text_color_ind", 1); // set text align if not set by user @@ -12633,7 +13503,7 @@ static void tickLabelAdjustment(const std::shared_ptr &tick_group, if (axis_type == "x") { text_elem->setAttribute("text_align_horizontal", GKS_K_TEXT_HALIGN_CENTER); - if (pos <= 0.5 * (window[2] + window[3]) || + if ((pos <= 0.5 * (window[2] + window[3]) && !(scale & GR_OPTION_FLIP_Y || y_flip)) || ((scale & GR_OPTION_FLIP_Y || y_flip) && pos > 0.5 * (window[2] + window[3]))) { text_elem->setAttribute("text_align_vertical", GKS_K_TEXT_VALIGN_TOP); @@ -12647,8 +13517,7 @@ static void tickLabelAdjustment(const std::shared_ptr &tick_group, { text_elem->setAttribute("text_align_vertical", GKS_K_TEXT_VALIGN_HALF); if ((pos <= 0.5 * (window[0] + window[1]) && !(scale & GR_OPTION_FLIP_X || x_flip)) || - ((scale & GR_OPTION_FLIP_X || x_flip) && pos > 0.5 * (window[0] + window[1]) && - tick_group->parentElement()->parentElement()->localName() != "colorbar")) + ((scale & GR_OPTION_FLIP_X || x_flip) && pos > 0.5 * (window[0] + window[1]))) { text_elem->setAttribute("text_align_horizontal", GKS_K_TEXT_HALIGN_RIGHT); } @@ -12658,18 +13527,21 @@ static void tickLabelAdjustment(const std::shared_ptr &tick_group, } } } - if (scientific_format == 2 || tick_group->parentElement()->hasAttribute("scientific_format")) - { - if (scientific_format != 2) - scientific_format = static_cast(tick_group->parentElement()->getAttribute("scientific_format")); - text_elem->setAttribute("scientific_format", scientific_format); - gr_setscientificformat(scientific_format); - } + text_elem->setAttribute("scientific_format", scientific_format); + } + + // remove all text children with _child_id > child_id + while (child_id < cur_child_count + child_id_org) + { + tick_group->querySelectors("text[_child_id=" + std::to_string(child_id++) + "]")->remove(); + if (child_id == cur_child_count + child_id_org && i >= cur_start && + tick_group->querySelectors("text[_child_id=" + std::to_string(child_id) + "]")) + tick_group->querySelectors("text[_child_id=" + std::to_string(child_id) + "]")->remove(); } } static void applyTickModificationMap(const std::shared_ptr &tick_group, - const std::shared_ptr &context, int child_id) + const std::shared_ptr &context, int child_id, del_values del) { std::shared_ptr text_elem = nullptr; bool tick_group_attr_changed = false, old_automatic_update = automatic_update; @@ -12692,24 +13564,35 @@ static void applyTickModificationMap(const std::shared_ptr &tick_g if (tick_value_to_map.find(value) != tick_value_to_map.end()) { auto key_value_map = tick_value_to_map[value]; - for (auto const &[attr, val] : key_value_map) + if (!key_value_map.empty()) { - if (str_equals_any(attr, "is_major", "line_color_ind", "line_spec", "line_type", "line_width", - "text_align_horizontal", "text_align_vertical", "tick_label", "tick_size", "value")) - { - tick_group->setAttribute(attr, val); - if (text_elem != nullptr && attr == "tick_label") - text_elem->setAttribute("text", val); - else if (text_elem == nullptr && attr == "tick_label") - tickLabelAdjustment(tick_group, child_id, del_values::recreate_own_children); - else if (str_equals_any(attr, "is_major", "value")) - tick_group->setAttribute("_update_required", true); - tick_group_attr_changed = true; - } - else if (str_equals_any(attr, "font", "font_precision", "scientific_format", "text", "text_color_ind", - "text_align_horizontal", "text_align_vertical", "x", "y")) + for (auto const &[attr, val] : key_value_map) { - text_elem->setAttribute(attr, val); + if (str_equals_any(attr, "is_major", "line_color_ind", "line_spec", "line_width", + "text_align_horizontal", "text_align_vertical", "tick_label", "tick_size", + "value")) + { + tick_group->setAttribute(attr, val); + if (attr == "tick_label") + { + tick_group->setAttribute("tick_label", val); + tickLabelAdjustment(tick_group, child_id, + text_elem != nullptr ? del_values::update_without_default : del); + } + else if (str_equals_any(attr, "is_major", "value")) + { + for (const auto &child : tick_group->children()) + { + child->setAttribute(attr, val); + } + } + tick_group_attr_changed = true; + } + else if (str_equals_any(attr, "font", "font_precision", "scientific_format", "text", "text_color_ind", + "text_align_horizontal", "text_align_vertical", "x", "y")) + { + if (text_elem != nullptr) text_elem->setAttribute(attr, val); + } } } if (tick_group_attr_changed) GRM::Render::processAttributes(tick_group); @@ -12721,8 +13604,6 @@ static void applyTickModificationMap(const std::shared_ptr &tick_g static void processTickGroup(const std::shared_ptr &element, const std::shared_ptr &context) { int child_id = 0, z_index = 0; - double x, y; - double window[4]; std::shared_ptr tick_elem, text, grid_line; del_values del = del_values::update_without_default; @@ -12733,15 +13614,6 @@ static void processTickGroup(const std::shared_ptr &element, const auto draw_grid = static_cast(element->parentElement()->getAttribute("draw_grid")); bool mirrored_axis = element->parentElement()->hasAttribute("mirrored_axis") && static_cast(element->parentElement()->getAttribute("mirrored_axis")); - // todo: window should come from axis if axis has window defined on it - window[0] = - static_cast(element->parentElement()->parentElement()->parentElement()->getAttribute("window_x_min")); - window[1] = - static_cast(element->parentElement()->parentElement()->parentElement()->getAttribute("window_x_max")); - window[2] = - static_cast(element->parentElement()->parentElement()->parentElement()->getAttribute("window_y_min")); - window[3] = - static_cast(element->parentElement()->parentElement()->parentElement()->getAttribute("window_y_max")); del = del_values(static_cast(element->getAttribute("_delete_children"))); clearOldChildren(&del, element); @@ -12821,7 +13693,7 @@ static void processTickGroup(const std::shared_ptr &element, const } tickLabelAdjustment(element, child_id, del); - applyTickModificationMap(element, context, child_id); + applyTickModificationMap(element, context, child_id, del); } static void processTick(const std::shared_ptr &element, const std::shared_ptr &context) @@ -13021,7 +13893,7 @@ static void volume(const std::shared_ptr &element, const std::shar static void processVolume(const std::shared_ptr &element, const std::shared_ptr &context) { - double dlim[2] = {INFINITY, -INFINITY}; + double dlim[2] = {INFINITY, (double)-INFINITY}; unsigned int z_length, dims; int algorithm = PLOT_DEFAULT_VOLUME_ALGORITHM; std::string algorithm_str; @@ -13067,11 +13939,11 @@ static void processVolume(const std::shared_ptr &element, const st gr_inqvpsize(&width, &height, &device_pixel_ratio); gr_setpicturesizeforvolume((int)(width * device_pixel_ratio), (int)(height * device_pixel_ratio)); } - const gr3_volume_2pass_t *volumeContext = + const gr3_volume_2pass_t *volume_context = gr_volume_2pass(z_dims_vec[0], z_dims_vec[1], z_dims_vec[2], &(z_vec[0]), algorithm, &d_min, &d_max, nullptr); std::ostringstream get_address; - get_address << volumeContext; + get_address << volume_context; element->setAttribute("_volume_context_address", get_address.str()); auto parent_element = element->parentElement(); @@ -13177,11 +14049,8 @@ void plotProcessWsWindowWsViewport(const std::shared_ptr &element, static_cast(active_figure->getAttribute("_previous_pixel_height")) != pixel_height)) { /* TODO: handle error return value? */ - auto figure_id_str = static_cast(active_figure->getAttribute("figure_id")); - if (starts_with(figure_id_str, "figure")) - { - figure_id_str = figure_id_str.substr(6); - } + auto figure_id_str = static_cast(active_figure->getAttribute("_figure_id")); + if (starts_with(figure_id_str, "figure")) figure_id_str = figure_id_str.substr(6); auto figure_id = std::stoi(figure_id_str); event_queue_enqueue_size_event(event_queue, figure_id, pixel_width, pixel_height); } @@ -13223,7 +14092,7 @@ static void plotCoordinateRanges(const std::shared_ptr &element, unsigned int current_point_count = 0; struct { - const char *subplot; + const char *plot; const char *series; } * current_range_keys, range_keys[] = {{"x_lim", "x_range"}, {"y_lim", "y_range"}, {"z_lim", "z_range"}, {"c_lim", "c_range"}}; @@ -13257,7 +14126,7 @@ static void plotCoordinateRanges(const std::shared_ptr &element, element->setAttribute("_z_lim_max", NAN); element->setAttribute("_c_lim_min", NAN); element->setAttribute("_c_lim_max", NAN); - kind = static_cast(element->getAttribute("kind")); + kind = static_cast(element->getAttribute("_kind")); if (!string_map_at(fmt_map, static_cast(kind.c_str()), static_cast(&fmt))) { std::stringstream ss; @@ -13281,9 +14150,9 @@ static void plotCoordinateRanges(const std::shared_ptr &element, continue; } /* Heatmaps need calculated range keys, so run the calculation even if limits are given */ - if (!element->hasAttribute(static_cast(current_range_keys->subplot) + "_min") || - !element->hasAttribute(static_cast(current_range_keys->subplot) + "_max") || - str_equals_any(kind, "heatmap", "marginal_heatmap", "polar_heatmap")) + if (!element->hasAttribute(static_cast(current_range_keys->plot) + "_min") || + !element->hasAttribute(static_cast(current_range_keys->plot) + "_max") || + str_equals_any(kind, "heatmap", "marginal_heatmap") || polar_kinds.count(kind) > 0) { std::shared_ptr series_parent = central_region; if (kind == "marginal_heatmap") series_parent = element; @@ -13347,7 +14216,8 @@ static void plotCoordinateRanges(const std::shared_ptr &element, current_max_component = y_length - 1; } else if (ends_with(series->localName(), kind) && - str_equals_any(kind, "heatmap", "marginal_heatmap", "polar_heatmap", "surface") && + str_equals_any(kind, "heatmap", "marginal_heatmap", "polar_heatmap", + "nonuniform_polar_heatmap", "surface") && str_equals_any((*current_component_name), "x", "y")) { /* in this case `x` or `y` (or both) are missing @@ -13467,29 +14337,29 @@ static void plotCoordinateRanges(const std::shared_ptr &element, series_count++; } } - if (element->hasAttribute(static_cast(current_range_keys->subplot) + "_min") && - element->hasAttribute(static_cast(current_range_keys->subplot) + "_max")) + if (element->hasAttribute(static_cast(current_range_keys->plot) + "_min") && + element->hasAttribute(static_cast(current_range_keys->plot) + "_max")) { min_component = static_cast( - element->getAttribute(static_cast(current_range_keys->subplot) + "_min")); + element->getAttribute(static_cast(current_range_keys->plot) + "_min")); max_component = static_cast( - element->getAttribute(static_cast(current_range_keys->subplot) + "_max")); - if (static_cast(current_range_keys->subplot) == "x_lim") + element->getAttribute(static_cast(current_range_keys->plot) + "_max")); + if (static_cast(current_range_keys->plot) == "x_lim") { element->setAttribute("_x_lim_min", min_component); element->setAttribute("_x_lim_max", max_component); } - else if (static_cast(current_range_keys->subplot) == "y_lim") + else if (static_cast(current_range_keys->plot) == "y_lim") { element->setAttribute("_y_lim_min", min_component); element->setAttribute("_y_lim_max", max_component); } - else if (static_cast(current_range_keys->subplot) == "z_lim") + else if (static_cast(current_range_keys->plot) == "z_lim") { element->setAttribute("_z_lim_min", min_component); element->setAttribute("_z_lim_max", max_component); } - else if (static_cast(current_range_keys->subplot) == "c_lim") + else if (static_cast(current_range_keys->plot) == "c_lim") { element->setAttribute("_c_lim_min", min_component); element->setAttribute("_c_lim_max", max_component); @@ -13509,12 +14379,12 @@ static void plotCoordinateRanges(const std::shared_ptr &element, min_component -= step; max_component += step; } - if (static_cast(current_range_keys->subplot) == "x_lim" && x_log) + if (static_cast(current_range_keys->plot) == "x_lim" && x_log) { min_component = (min_component > 0) ? min_component : 1; max_component = (max_component > 0) ? max_component : min_component + 1; } - if (static_cast(current_range_keys->subplot) == "y_lim" && y_log) + if (static_cast(current_range_keys->plot) == "y_lim" && y_log) { min_component = (min_component > 0) ? min_component : 1; max_component = (max_component > 0) ? max_component : min_component + 1; @@ -13531,7 +14401,7 @@ static void plotCoordinateRanges(const std::shared_ptr &element, if (!starts_with(series->localName(), "series")) continue; } } - if (static_cast(current_range_keys->subplot) == "x_lim") + if (static_cast(current_range_keys->plot) == "x_lim") { if (orientation == "horizontal") { @@ -13544,7 +14414,7 @@ static void plotCoordinateRanges(const std::shared_ptr &element, element->setAttribute("_y_lim_max", max_component); } } - else if (static_cast(current_range_keys->subplot) == "y_lim") + else if (static_cast(current_range_keys->plot) == "y_lim") { if (orientation == "horizontal") { @@ -13557,12 +14427,12 @@ static void plotCoordinateRanges(const std::shared_ptr &element, element->setAttribute("_x_lim_max", max_component); } } - else if (static_cast(current_range_keys->subplot) == "z_lim") + else if (static_cast(current_range_keys->plot) == "z_lim") { element->setAttribute("_z_lim_min", min_component); element->setAttribute("_z_lim_max", max_component); } - else if (static_cast(current_range_keys->subplot) == "c_lim") + else if (static_cast(current_range_keys->plot) == "c_lim") { element->setAttribute("_c_lim_min", min_component); element->setAttribute("_c_lim_max", max_component); @@ -13572,8 +14442,28 @@ static void plotCoordinateRanges(const std::shared_ptr &element, ++current_component_name; } } - else if (kind == "polar_histogram") + if (polar_kinds.count(kind) > 0) { + if (kind != "polar_histogram") + { + if (kind == "nonuniform_polar_heatmap") kind = "polar_heatmap"; + + auto series_vec = element->getElementsByTagName("series_" + kind); + auto series = series_vec[0]; + + // set calc ranges _x_ranges for later distinction from user ranges + // Todo: use this attributes somewhere + auto xmin = static_cast(series->getAttribute("x_range_min")); + auto xmax = static_cast(series->getAttribute("x_range_max")); + series->setAttribute("_x_range_min", xmin); + series->setAttribute("_x_range_max", xmax); + + auto ymin = static_cast(element->getAttribute("_y_lim_min")); + auto ymax = static_cast(element->getAttribute("_y_lim_max")); + central_region->setAttribute("r_min", ymin); + central_region->setAttribute("r_max", ymax); + } + // this is needed for interactions replaces gr_setwindow(-1,1,-1,1); element->setAttribute("_x_lim_min", -1.0); element->setAttribute("_x_lim_max", 1.0); element->setAttribute("_y_lim_min", -1.0); @@ -13643,30 +14533,30 @@ static void plotCoordinateRanges(const std::shared_ptr &element, { double min_component = (kind == "imshow" ? 0.0 : -1.0); double max_component = 1.0; - if (element->hasAttribute(static_cast(current_range_keys->subplot) + "_min") && - element->hasAttribute(static_cast(current_range_keys->subplot) + "_max")) + if (element->hasAttribute(static_cast(current_range_keys->plot) + "_min") && + element->hasAttribute(static_cast(current_range_keys->plot) + "_max")) { min_component = static_cast( - element->getAttribute(static_cast(current_range_keys->subplot) + "_min")); + element->getAttribute(static_cast(current_range_keys->plot) + "_min")); max_component = static_cast( - element->getAttribute(static_cast(current_range_keys->subplot) + "_max")); + element->getAttribute(static_cast(current_range_keys->plot) + "_max")); } - if (static_cast(current_range_keys->subplot) == "x_lim") + if (static_cast(current_range_keys->plot) == "x_lim") { element->setAttribute("_x_lim_min", min_component); element->setAttribute("_x_lim_max", max_component); } - else if (static_cast(current_range_keys->subplot) == "y_lim") + else if (static_cast(current_range_keys->plot) == "y_lim") { element->setAttribute("_y_lim_min", min_component); element->setAttribute("_y_lim_max", max_component); } - else if (static_cast(current_range_keys->subplot) == "z_lim") + else if (static_cast(current_range_keys->plot) == "z_lim") { element->setAttribute("_z_lim_min", min_component); element->setAttribute("_z_lim_max", max_component); } - else if (static_cast(current_range_keys->subplot) == "c_lim") + else if (static_cast(current_range_keys->plot) == "c_lim") { element->setAttribute("_c_lim_min", min_component); element->setAttribute("_c_lim_max", max_component); @@ -13676,7 +14566,7 @@ static void plotCoordinateRanges(const std::shared_ptr &element, } else if (kind == "barplot") { - double x_min = 0.0, x_max = -DBL_MAX, y_min = DBL_MAX, y_max = -DBL_MAX; + double x_min = DBL_MAX, x_max = -DBL_MAX, y_min = DBL_MAX, y_max = -DBL_MAX; std::string orientation = PLOT_DEFAULT_ORIENTATION; if (!element->hasAttribute("x_lim_min") || !element->hasAttribute("x_lim_max")) @@ -13685,45 +14575,53 @@ static void plotCoordinateRanges(const std::shared_ptr &element, for (const auto &series : central_region->children()) { - if (!starts_with(series->localName(), "series")) continue; - if (series->hasAttribute("style")) style = static_cast(series->getAttribute("style")); - if (str_equals_any(style, "lined", "stacked")) - { - x_max = series_count + 1; - } - else + if (series->localName() != "series_barplot") continue; + if (series->hasAttribute("x_range_min") && series->hasAttribute("x_range_max")) { + if (series->hasAttribute("orientation")) + orientation = static_cast(series->getAttribute("orientation")); auto key = static_cast(series->getAttribute("y")); auto y = GRM::get>((*context)[key]); current_point_count = y.size(); - x_max = grm_max(current_point_count + 1, x_max); - } - } - - for (const auto &series : central_region->children()) - { - if (!starts_with(series->localName(), "series")) continue; - if (series->hasAttribute("orientation")) - orientation = static_cast(series->getAttribute("orientation")); - auto key = static_cast(series->getAttribute("y")); - auto y = GRM::get>((*context)[key]); - current_point_count = y.size(); - if (series->hasAttribute("x_range_min") && series->hasAttribute("x_range_max")) - { xmin = static_cast(series->getAttribute("x_range_min")); xmax = static_cast(series->getAttribute("x_range_max")); double step_x = (xmax - xmin) / (current_point_count - 1); if (!str_equals_any(style, "lined", "stacked")) { - x_min = xmin - step_x; - x_max = xmax + step_x; + x_min = grm_min(x_min, xmin - step_x); + x_max = grm_max(x_max, xmax + step_x); + } + else + { + if (x_min == DBL_MAX) x_min = xmin; + if (style == "stacked") + x_min = xmin - series_count; + else + x_min = grm_min(x_min, xmin - (x_max - 1)); + if (x_max == -DBL_MAX) x_max = xmax; + if (style == "stacked") + x_max = xmin + series_count; + else + x_max = grm_max(x_max, xmin + (x_max - 1)); + } + } + else + { + if (series->hasAttribute("style")) + style = static_cast(series->getAttribute("style")); + if (str_equals_any(style, "lined", "stacked")) + { + x_max = series_count + 1; } else { - x_min = xmin - (x_max - 1); - x_max = xmin + (x_max - 1); + auto key = static_cast(series->getAttribute("y")); + auto y = GRM::get>((*context)[key]); + current_point_count = y.size(); + x_max = grm_max(current_point_count + 1, x_max); } + x_min = 0; } } } @@ -13738,7 +14636,7 @@ static void plotCoordinateRanges(const std::shared_ptr &element, double ymin, ymax; for (const auto &series : central_region->children()) { - if (!starts_with(series->localName(), "series")) continue; + if (series->localName() != "series_barplot") continue; if (series->hasAttribute("style")) style = static_cast(series->getAttribute("style")); if (series->hasAttribute("orientation")) orientation = static_cast(series->getAttribute("orientation")); @@ -13753,18 +14651,18 @@ static void plotCoordinateRanges(const std::shared_ptr &element, y_min = grm_min(y_min, ymin); if (style == "stacked") { - double tmp_ymax; - tmp_ymax = ymin; + double tmp_ymax, tmp_ymin = 0; + if (element->hasAttribute("y_log") && static_cast(element->getAttribute("y_log"))) + tmp_ymin = 1; for (i = 0; i < current_point_count; i++) { - if (y_min < 0) - { - tmp_ymax += fabs(y[i]); - } - else - { - tmp_ymax += y[i] - y_min; - } + if (y[i] < 0) tmp_ymin += y[i]; + } + y_min = grm_min(y_min, tmp_ymin); + tmp_ymax = tmp_ymin; + for (i = 0; i < current_point_count; i++) + { + tmp_ymax += (y_min < 0) ? fabs(y[i]) : y[i] - y_min; } y_max = grm_max(y_max, tmp_ymax); } @@ -13798,7 +14696,7 @@ static void plotCoordinateRanges(const std::shared_ptr &element, } else if (kind == "hist") { - double x_min = 0.0, x_max = 0.0, y_min = 0.0, y_max = 0.0; + double x_min = DBL_MAX, x_max = -DBL_MAX, y_min = DBL_MAX, y_max = -DBL_MAX; std::string orientation = PLOT_DEFAULT_ORIENTATION; bool is_horizontal; @@ -13810,7 +14708,7 @@ static void plotCoordinateRanges(const std::shared_ptr &element, orientation = static_cast(series->getAttribute("orientation")); is_horizontal = orientation == "horizontal"; if (!starts_with(series->localName(), "series")) continue; - double current_y_min = DBL_MAX, current_y_max = -DBL_MAX; + double current_y_min = 0.0, current_y_max = 0.0; if (!series->hasAttribute("bins")) histBins(series, context); auto bins_key = static_cast(series->getAttribute("bins")); @@ -13822,19 +14720,27 @@ static void plotCoordinateRanges(const std::shared_ptr &element, current_y_min = grm_min(current_y_min, bins[i]); current_y_max = grm_max(current_y_max, bins[i]); } - - y_min = grm_min(current_y_min, y_min); + // y_max is a bit strange cause it doesn't get affected by y_range, the hist displayes the sum of 1 + // or more y-values in each bar -> use the data-values along with the ranges to find the real max y_max = grm_max(current_y_max, y_max); - x_max = current_point_count - 1; if (series->hasAttribute("y_range_min") && series->hasAttribute("y_range_max")) { - y_min = static_cast(series->getAttribute("y_range_min")); - y_max = static_cast(series->getAttribute("y_range_max")); + y_min = grm_min(y_min, static_cast(series->getAttribute("y_range_min"))); + y_max = grm_max(y_max, static_cast(series->getAttribute("y_range_max"))); + } + else + { + y_min = grm_min(current_y_min, y_min); } if (series->hasAttribute("x_range_min") && series->hasAttribute("x_range_max")) { - x_min = static_cast(series->getAttribute("x_range_min")); - x_max = static_cast(series->getAttribute("x_range_max")); + x_min = grm_min(x_min, static_cast(series->getAttribute("x_range_min"))); + x_max = grm_max(x_max, static_cast(series->getAttribute("x_range_max"))); + } + else + { + x_min = 0.0; + x_max = num_bins - 1; } } if (is_horizontal) @@ -13855,7 +14761,7 @@ static void plotCoordinateRanges(const std::shared_ptr &element, } else if (str_equals_any(kind, "stem", "stairs")) { - double x_min = 0.0, x_max = 0.0, y_min = 0.0, y_max = 0.0; + double x_min = DBL_MAX, x_max = -DBL_MAX, y_min = DBL_MAX, y_max = -DBL_MAX; std::string orientation = PLOT_DEFAULT_ORIENTATION; bool is_horizontal; @@ -13868,8 +14774,8 @@ static void plotCoordinateRanges(const std::shared_ptr &element, if (series->hasAttribute("x_range_min") && series->hasAttribute("x_range_max") && !(element->hasAttribute("x_lim_min") && element->hasAttribute("x_lim_max"))) { - x_min = static_cast(series->getAttribute("x_range_min")); - x_max = static_cast(series->getAttribute("x_range_max")); + x_min = grm_min(x_min, static_cast(series->getAttribute("x_range_min"))); + x_max = grm_max(x_max, static_cast(series->getAttribute("x_range_max"))); if (is_horizontal) { element->setAttribute("_x_lim_min", x_min); @@ -13884,8 +14790,8 @@ static void plotCoordinateRanges(const std::shared_ptr &element, if (series->hasAttribute("y_range_min") && series->hasAttribute("y_range_max") && !(element->hasAttribute("y_lim_min") && element->hasAttribute("y_lim_max"))) { - y_min = static_cast(series->getAttribute("y_range_min")); - y_max = static_cast(series->getAttribute("y_range_max")); + y_min = grm_min(y_min, static_cast(series->getAttribute("y_range_min"))); + y_max = grm_max(y_max, static_cast(series->getAttribute("y_range_max"))); if (is_horizontal) { element->setAttribute("_y_lim_min", y_min); @@ -13915,13 +14821,12 @@ static void processSideRegion(const std::shared_ptr &element, if (element->hasAttribute("text_content")) { - auto kind = static_cast(plot_parent->getAttribute("kind")); + auto kind = static_cast(plot_parent->getAttribute("_kind")); auto text = static_cast(element->getAttribute("text_content")); auto location = static_cast(element->getAttribute("location")); if (((del != del_values::update_without_default && del != del_values::update_with_default)) && !text.empty() && - kind != "imshow" && - (std::find(kinds_3d.begin(), kinds_3d.end(), kind) == kinds_3d.end() || location == "top")) + kind != "imshow" && (kinds_3d.find(kind) == kinds_3d.end() || location == "top")) { auto text_elem = global_render->createTextRegion(); text_elem->setAttribute("_child_id", child_id++); @@ -13953,24 +14858,22 @@ static void processCoordinateSystem(const std::shared_ptr &element { int child_id = 0; del_values del = del_values::update_without_default; - std::shared_ptr polar_axes, axis, grid_3d, axes_3d, titles_3d; + std::shared_ptr axis, grid_3d, axes_3d, titles_3d; std::string type; auto plot_parent = element->parentElement(); getPlotParent(plot_parent); - auto kind = static_cast(plot_parent->getAttribute("kind")); + auto kind = static_cast(plot_parent->getAttribute("_kind")); del = del_values(static_cast(element->getAttribute("_delete_children"))); clearOldChildren(&del, element); for (const auto &parent_child : element->parentElement()->children()) { - if (parent_child->localName() == "series_barplot" || parent_child->localName() == "series_stem") + if (str_equals_any(parent_child->localName(), "series_barplot", "series_stem")) { auto series_kind = static_cast(parent_child->getAttribute("kind")); - if (series_kind == "barplot" || series_kind == "stem") - { - if (!element->hasAttribute("y_line")) element->setAttribute("y_line", true); - } + if (str_equals_any(series_kind, "barplot", "stem") && !element->hasAttribute("y_line")) + element->setAttribute("y_line", true); break; } } @@ -14017,40 +14920,30 @@ static void processCoordinateSystem(const std::shared_ptr &element if (type == "polar") { // create polar coordinate system - int angle_ticks = 8, phiflip = 0; - std::string norm = "count"; - double tick = 0.0; + std::shared_ptr rho_axes, theta_axes; - if (element->hasAttribute("angle_ticks")) - { - angle_ticks = static_cast(element->getAttribute("angle_ticks")); - } - - if (element->hasAttribute("phi_flip")) + if (del != del_values::update_without_default && del != del_values::update_with_default) { - phiflip = static_cast(element->getAttribute("phi_flip")); + rho_axes = global_render->createRhoAxes(); + rho_axes->setAttribute("_child_id", child_id++); + element->append(rho_axes); } - - if (kind == "polar_histogram") + else { - if (element->hasAttribute("normalization")) - { - norm = static_cast(element->getAttribute("normalization")); - } - tick = 1.0; + rho_axes = element->querySelectors("rho_axes[_child_id=" + std::to_string(child_id++) + "]"); + if (rho_axes != nullptr) global_render->createRhoAxes(rho_axes); } if (del != del_values::update_without_default && del != del_values::update_with_default) { - polar_axes = global_render->createDrawPolarAxes(angle_ticks, kind, phiflip, norm, tick, 0.0); - polar_axes->setAttribute("_child_id", child_id++); - element->append(polar_axes); + theta_axes = global_render->createThetaAxes(); + theta_axes->setAttribute("_child_id", child_id++); + element->append(theta_axes); } else { - polar_axes = element->querySelectors("polar_axes[_child_id=" + std::to_string(child_id++) + "]"); - if (polar_axes != nullptr) - global_render->createDrawPolarAxes(angle_ticks, kind, phiflip, norm, tick, 0.0, polar_axes); + theta_axes = element->querySelectors("theta_axes[_child_id=" + std::to_string(child_id++) + "]"); + if (theta_axes != nullptr) global_render->createThetaAxes(theta_axes); } } else @@ -14068,6 +14961,7 @@ static void processCoordinateSystem(const std::shared_ptr &element if (type == "3d") { + std::string x_label, y_label, z_label; bool z_grid; if (element->hasAttribute("z_grid")) { @@ -14168,12 +15062,9 @@ static void processCoordinateSystem(const std::shared_ptr &element axes_3d->setAttribute("z_index", 7); } - std::string x_label = - (element->hasAttribute("x_label")) ? static_cast(element->getAttribute("x_label")) : ""; - std::string y_label = - (element->hasAttribute("y_label")) ? static_cast(element->getAttribute("y_label")) : ""; - std::string z_label = - (element->hasAttribute("z_label")) ? static_cast(element->getAttribute("z_label")) : ""; + x_label = element->hasAttribute("x_label") ? static_cast(element->getAttribute("x_label")) : ""; + y_label = element->hasAttribute("y_label") ? static_cast(element->getAttribute("y_label")) : ""; + z_label = element->hasAttribute("z_label") ? static_cast(element->getAttribute("z_label")) : ""; if (!x_label.empty() || !y_label.empty() || !z_label.empty()) { if (del != del_values::update_without_default && del != del_values::update_with_default) @@ -14236,8 +15127,8 @@ static void processCoordinateSystem(const std::shared_ptr &element static void processPlot(const std::shared_ptr &element, const std::shared_ptr &context) { std::shared_ptr central_region, central_region_parent = element; - if (static_cast(element->getAttribute("kind")) == "marginal_heatmap") - central_region_parent = element->querySelectors("marginal_heatmap_plot"); + auto kind = static_cast(element->getAttribute("_kind")); + if (kind == "marginal_heatmap") central_region_parent = element->querySelectors("marginal_heatmap_plot"); for (const auto &child : central_region_parent->children()) { @@ -14248,6 +15139,21 @@ static void processPlot(const std::shared_ptr &element, const std: } } + if (polar_kinds.count(kind) > 0) + { + if (element->hasAttribute("x_lim_min") && element->hasAttribute("x_lim_max")) + { + auto x_lim_min = static_cast(element->getAttribute("x_lim_min")); + auto x_lim_max = static_cast(element->getAttribute("x_lim_max")); + if (!grm_isnan(x_lim_min) && !grm_isnan(x_lim_max)) gr_setclipsector(x_lim_min, x_lim_max); + } + if (!element->hasAttribute("polar_with_pan") || !static_cast(element->getAttribute("polar_with_pan"))) + { + global_render->setClipRegion(central_region, 1); + global_render->setSelectSpecificXform(central_region, 1); + } + } + // set the x-, y- and z-data to NAN if the value is <= 0 // if the plot contains the marginal_heatmap_plot the marginal_heatmap should be child in the following for for (const auto &child : (central_region_parent == element) ? central_region->children() : element->children()) @@ -14305,12 +15211,12 @@ static void processPlot(const std::shared_ptr &element, const std: if (static_cast(element->getAttribute("x_log")) && child->hasAttribute("_x_org")) { - double x_min = INFINITY, x_max = -INFINITY; + double x_min = INFINITY, x_max = (double)-INFINITY; auto x = static_cast(child->getAttribute("_x_org")); auto x_vec = GRM::get>((*context)[x]); auto x_len = x_vec.size(); - if (static_cast(element->getAttribute("kind")) == "volume") + if (kind == "volume") { fprintf(stderr, "The option x_log is not supported for volume. It will be set to false.\n"); element->setAttribute("x_log", 0); @@ -14345,12 +15251,12 @@ static void processPlot(const std::shared_ptr &element, const std: } if (static_cast(element->getAttribute("y_log")) && child->hasAttribute("_y_org")) { - double y_min = INFINITY, y_max = -INFINITY; + double y_min = INFINITY, y_max = (double)-INFINITY; auto y = static_cast(child->getAttribute("_y_org")); auto y_vec = GRM::get>((*context)[y]); auto y_len = y_vec.size(); - if (static_cast(element->getAttribute("kind")) == "volume") + if (kind == "volume") { fprintf(stderr, "The option y_log is not supported for volume. It will be set to false.\n"); element->setAttribute("y_log", 0); @@ -14379,20 +15285,21 @@ static void processPlot(const std::shared_ptr &element, const std: (*context)["y" + str] = y_vec; child->setAttribute("y", "y" + str); + if (kind == "barplot" && y_min <= 0) y_min = 1; if (child->hasAttribute("y_range_min")) child->setAttribute("y_range_min", y_min); if (child->hasAttribute("y_range_max")) child->setAttribute("y_range_max", y_max); } } if (static_cast(element->getAttribute("z_log")) && child->hasAttribute("_z_org")) { - double z_min = INFINITY, z_max = -INFINITY; + double z_min = INFINITY, z_max = (double)-INFINITY; auto z = static_cast(child->getAttribute("_z_org")); auto z_vec = GRM::get>((*context)[z]); auto z_len = z_vec.size(); - if (static_cast(element->getAttribute("kind")) == "volume") + if (kind == "volume") { - fprintf(stderr, "The option y_log is not supported for volume. It will be set to false.\n"); + fprintf(stderr, "The option z_log is not supported for volume. It will be set to false.\n"); element->setAttribute("z_log", 0); } else @@ -14437,10 +15344,7 @@ static void processPlot(const std::shared_ptr &element, const std: // todo: there are cases that element does not have char_height set // char_height is always calculated (and set in the gr) in calculateCharHeight // it is however not stored on the element as it can be calculated from other attributes - if (element->hasAttribute("char_height")) - { - processCharHeight(element); - } + if (element->hasAttribute("char_height")) processCharHeight(element); GRM::Render::processLimits(element); GRM::Render::processScale(element); /* needs to be set before flip is processed */ @@ -14456,17 +15360,13 @@ static void processPlot(const std::shared_ptr &element, const std: { if (child->localName() == "series_barplot" || child->localName() == "series_polar_histogram") { - auto kind = static_cast(child->getAttribute("kind")); - if (kindNameToFunc.find(kind) != kindNameToFunc.end()) - { - kindNameToFunc[kind](element, context); - } + kind = static_cast(child->getAttribute("kind")); + if (kindNameToFunc.find(kind) != kindNameToFunc.end()) kindNameToFunc[kind](element, context); break; } } std::shared_ptr side_region; - auto kind = static_cast(element->getAttribute("kind")); if (!element->querySelectors("side_region[location=\"right\"]")) { @@ -14506,9 +15406,10 @@ static void processSeries(const std::shared_ptr &element, const st {std::string("line"), processLine}, {std::string("pie"), processPie}, {std::string("plot3"), processPlot3}, - {std::string("polar"), processPolar}, {std::string("polar_heatmap"), processPolarHeatmap}, {std::string("polar_histogram"), processPolarHistogram}, + {std::string("polar_line"), processPolarLine}, + {std::string("polar_scatter"), processPolarScatter}, {std::string("quiver"), PushDrawableToZQueue(processQuiver)}, {std::string("scatter"), processScatter}, {std::string("scatter3"), processScatter3}, @@ -14523,7 +15424,7 @@ static void processSeries(const std::shared_ptr &element, const st }; auto kind = static_cast(element->getAttribute("kind")); - auto plot_elem = getSubplotElement(element); + auto plot_elem = getPlotElement(element); if (auto search = seriesNameToFunc.find(kind); search != seriesNameToFunc.end()) { @@ -14570,16 +15471,17 @@ static void processElement(const std::shared_ptr &element, const s static std::map, const std::shared_ptr)>> elemStringToFunc{ + {std::string("angle_line"), processAngleLine}, + {std::string("arc_grid_line"), processArcGridLine}, {std::string("axes_3d"), PushDrawableToZQueue(processAxes3d)}, {std::string("axis"), processAxis}, {std::string("bar"), processBar}, - {std::string("cellarray"), PushDrawableToZQueue(processCellArray)}, + {std::string("cell_array"), PushDrawableToZQueue(processCellArray)}, {std::string("colorbar"), processColorbar}, {std::string("coordinate_system"), processCoordinateSystem}, {std::string("error_bar"), processErrorBar}, {std::string("error_bars"), processErrorBars}, {std::string("legend"), processLegend}, - {std::string("polar_axes"), processPolarAxes}, {std::string("draw_arc"), PushDrawableToZQueue(processDrawArc)}, {std::string("draw_graphics"), PushDrawableToZQueue(processDrawGraphics)}, {std::string("draw_image"), PushDrawableToZQueue(processDrawImage)}, @@ -14594,30 +15496,32 @@ static void processElement(const std::shared_ptr &element, const s {std::string("isosurface_render"), PushDrawableToZQueue(processIsosurfaceRender)}, {std::string("layout_grid"), PushDrawableToZQueue(processLayoutGrid)}, {std::string("marginal_heatmap_plot"), processMarginalHeatmapPlot}, - {std::string("nonuniform_polarcellarray"), PushDrawableToZQueue(processNonUniformPolarCellArray)}, - {std::string("nonuniformcellarray"), PushDrawableToZQueue(processNonuniformcellarray)}, + {std::string("nonuniform_polar_cell_array"), PushDrawableToZQueue(processNonUniformPolarCellArray)}, + {std::string("nonuniform_cell_array"), PushDrawableToZQueue(processNonuniformCellArray)}, {std::string("panzoom"), PushDrawableToZQueue(processPanzoom)}, {std::string("pie_segment"), processPieSegment}, {std::string("polar_bar"), processPolarBar}, - {std::string("polarcellarray"), PushDrawableToZQueue(processPolarCellArray)}, + {std::string("polar_cell_array"), PushDrawableToZQueue(processPolarCellArray)}, {std::string("polyline"), PushDrawableToZQueue(processPolyline)}, {std::string("polyline_3d"), PushDrawableToZQueue(processPolyline3d)}, {std::string("polymarker"), PushDrawableToZQueue(processPolymarker)}, {std::string("polymarker_3d"), PushDrawableToZQueue(processPolymarker3d)}, + {std::string("rho_axes"), processRhoAxes}, {std::string("series"), processSeries}, {std::string("side_region"), processSideRegion}, {std::string("side_plot_region"), processSidePlotRegion}, {std::string("text"), PushDrawableToZQueue(processText)}, {std::string("text_region"), processTextRegion}, + {std::string("theta_axes"), processThetaAxes}, {std::string("tick"), PushDrawableToZQueue(processTick)}, {std::string("tick_group"), processTickGroup}, {std::string("titles_3d"), PushDrawableToZQueue(processTitles3d)}, }; /* Modifier */ - if (str_equals_any(element->localName(), "axes_text_group", "axis", "central_region", "figure", "plot", "label", - "labels_group", "root", "layout_grid_element", "side_region", "text_region", "side_plot_region", - "tick_group")) + if (str_equals_any(element->localName(), "axis", "central_region", "figure", "plot", "label", "labels_group", "root", + "layout_grid_element", "rho_axes", "side_region", "text_region", "side_plot_region", "tick_group", + "theta_axes", "arc_grid_line", "angle_line")) { bool old_state = automatic_update; automatic_update = false; @@ -14631,7 +15535,7 @@ static void processElement(const std::shared_ptr &element, const s { std::shared_ptr central_region_parent = element; processPlot(element, context); - if (static_cast(element->getAttribute("kind")) == "marginal_heatmap") + if (static_cast(element->getAttribute("_kind")) == "marginal_heatmap") central_region_parent = element->children()[0]; // if the kind is marginal_heatmap plot can only has 1 child // and this child is the marginal_heatmap_plot @@ -14653,10 +15557,14 @@ static void processElement(const std::shared_ptr &element, const s { calculateViewport(element); } + if (element->localName() == "angle_line") processAngleLine(element, context); + if (element->localName() == "arc_grid_line") processArcGridLine(element, context); + if (element->localName() == "axis") processAxis(element, context); + if (element->localName() == "rho_axes") processRhoAxes(element, context); + if (element->localName() == "side_plot_region") processSidePlotRegion(element, context); if (element->localName() == "side_region") processSideRegion(element, context); if (element->localName() == "text_region") processTextRegion(element, context); - if (element->localName() == "side_plot_region") processSidePlotRegion(element, context); - if (element->localName() == "axis") processAxis(element, context); + if (element->localName() == "theta_axes") processThetaAxes(element, context); if (element->localName() == "tick_group") processTickGroup(element, context); GRM::Render::processAttributes(element); automatic_update = old_state; @@ -14675,9 +15583,9 @@ static void processElement(const std::shared_ptr &element, const s // TODO: something like series_contour shouldn't be in this list if (!automatic_update || ((static_cast(global_root->getAttribute("_modified")) && - (str_equals_any(element->localName(), "axes_3d", "cellarray", "colorbar", "draw_arc", "draw_image", + (str_equals_any(element->localName(), "axes_3d", "cell_array", "colorbar", "draw_arc", "draw_image", "draw_rect", "fill_arc", "fill_area", "fill_rect", "grid", "grid_3d", "legend", - "nonuniform_polarcellarray", "nonuniformcellarray", "polarcellarray", "polyline", + "nonuniform_polar_cell_array", "nonuniform_cell_array", "polar_cell_array", "polyline", "polyline_3d", "polymarker", "polymarker_3d", "series_contour", "series_contourf", "text", "titles_3d", "coordinate_system", "series_hexbin", "series_isosurface", "series_quiver", "series_shade", "series_surface", "series_tricontour", "series_trisurface", @@ -14721,8 +15629,8 @@ static void processElement(const std::shared_ptr &element, const s { for (const auto &child : element->children()) { - if (!str_equals_any(element->localName(), "axes_text_group", "figure", "plot", "label", - "labels_group", "root", "layout_grid_element")) + if (!str_equals_any(element->localName(), "figure", "plot", "label", "labels_group", "root", + "layout_grid_element")) { child->setAttribute("_update_required", true); resetOldBoundingBoxes(child); @@ -14777,10 +15685,7 @@ static void renderHelper(const std::shared_ptr &element, const std renderHelper(child, context); } } - if (bounding_boxes && !isDrawable(element)) - { - gr_cancelbboxcallback(); - } + if (bounding_boxes && !isDrawable(element)) gr_cancelbboxcallback(); custom_color_index_manager.restorestate(); z_index_manager.restorestate(); @@ -14824,9 +15729,7 @@ static void missingBboxCalculator(const std::shared_ptr &element, elem_bbox_ymax == -DBL_MAX)) { if (static_cast(element->getAttribute("_bbox_id")) != -1) - { - element->setAttribute("_bbox_id", bounding_id++); - } + element->setAttribute("_bbox_id", bounding_id++); element->setAttribute("_bbox_x_min", elem_bbox_xmin); element->setAttribute("_bbox_x_max", elem_bbox_xmax); element->setAttribute("_bbox_y_min", elem_bbox_ymin); @@ -14862,10 +15765,7 @@ static void renderZQueue(const std::shared_ptr &context) custom_color_index_manager.selectcontext(drawable->getGrContextId()); drawable->draw(); - if (bounding_boxes) - { - gr_cancelbboxcallback(); - } + if (bounding_boxes) gr_cancelbboxcallback(); } gr_context_id_manager.markAllIdsAsUnused(); parent_to_context = {}; @@ -14880,29 +15780,28 @@ static void initializeGridElements(const std::shared_ptr &element, { for (const auto &child : element->children()) { - if (child->localName() != "layout_grid_element" && child->localName() != "layout_grid") - { - return; - } - - double abs_height = (child->hasAttribute("absolute_height")) - ? static_cast(child->getAttribute("absolute_height")) - : -1; - double abs_width = - (child->hasAttribute("absolute_width")) ? static_cast(child->getAttribute("absolute_width")) : -1; - int abs_height_pxl = (child->hasAttribute("absolute_height_pxl")) - ? static_cast(child->getAttribute("absolute_height_pxl")) + if (child->localName() != "layout_grid_element" && child->localName() != "layout_grid") return; + + auto abs_height = (child->hasAttribute("absolute_height")) + ? static_cast(child->getAttribute("absolute_height")) + : -1.0; + auto abs_width = (child->hasAttribute("absolute_width")) + ? static_cast(child->getAttribute("absolute_width")) + : -1.0; + auto abs_height_pxl = (child->hasAttribute("absolute_height_pxl")) + ? static_cast(child->getAttribute("absolute_height_pxl")) + : -1; + auto abs_width_pxl = (child->hasAttribute("absolute_width_pxl")) + ? static_cast(child->getAttribute("absolute_width_pxl")) : -1; - int abs_width_pxl = (child->hasAttribute("absolute_width_pxl")) - ? static_cast(child->getAttribute("absolute_width_pxl")) - : -1; - double relative_height = (child->hasAttribute("relative_height")) - ? static_cast(child->getAttribute("relative_height")) - : -1; - auto relative_width = - (child->hasAttribute("relative_width")) ? static_cast(child->getAttribute("relative_width")) : -1; + auto relative_height = (child->hasAttribute("relative_height")) + ? static_cast(child->getAttribute("relative_height")) + : -1.0; + auto relative_width = (child->hasAttribute("relative_width")) + ? static_cast(child->getAttribute("relative_width")) + : -1.0; auto aspect_ratio = - (child->hasAttribute("aspect_ratio")) ? static_cast(child->getAttribute("aspect_ratio")) : -1; + (child->hasAttribute("aspect_ratio")) ? static_cast(child->getAttribute("aspect_ratio")) : -1.0; auto fit_parents_height = static_cast(child->getAttribute("fit_parents_height")); auto fit_parents_width = static_cast(child->getAttribute("fit_parents_width")); auto row_start = static_cast(child->getAttribute("start_row")); @@ -14916,19 +15815,19 @@ static void initializeGridElements(const std::shared_ptr &element, auto *cur_grid_element = new grm::GridElement(abs_height, abs_width, abs_height_pxl, abs_width_pxl, fit_parents_height, fit_parents_width, relative_height, relative_width, aspect_ratio); - cur_grid_element->elementInDOM = child; + cur_grid_element->element_in_dom = child; grid->setElement(slice, cur_grid_element); } if (child->localName() == "layout_grid") { - int nrows = static_cast(child->getAttribute("num_row")); - int ncols = static_cast(child->getAttribute("num_col")); + auto nrows = static_cast(child->getAttribute("num_row")); + auto ncols = static_cast(child->getAttribute("num_col")); auto *cur_grid = new grm::Grid(nrows, ncols, abs_height, abs_width, abs_height_pxl, abs_width_pxl, fit_parents_height, fit_parents_width, relative_height, relative_width, aspect_ratio); - cur_grid->elementInDOM = child; + cur_grid->element_in_dom = child; grid->setElement(slice, cur_grid); initializeGridElements(child, cur_grid); } @@ -14945,8 +15844,8 @@ static void finalizeGrid(const std::shared_ptr &figure) { if (child->localName() == "layout_grid") { - int nrows = static_cast(child->getAttribute("num_row")); - int ncols = static_cast(child->getAttribute("num_col")); + auto nrows = static_cast(child->getAttribute("num_row")); + auto ncols = static_cast(child->getAttribute("num_col")); root_grid = new grm::Grid(nrows, ncols); child->setAttribute("plot_x_min", 0); child->setAttribute("plot_x_max", 1); @@ -14954,7 +15853,7 @@ static void finalizeGrid(const std::shared_ptr &figure) child->setAttribute("plot_y_max", 1); initializeGridElements(child, root_grid); - root_grid->finalizeSubplot(); + root_grid->finalizePlot(); break; } } @@ -14964,7 +15863,7 @@ static void finalizeGrid(const std::shared_ptr &figure) static void applyCentralRegionDefaults(const std::shared_ptr ¢ral_region) { auto plot = central_region->parentElement(); - auto kind = static_cast(plot->getAttribute("kind")); + auto kind = static_cast(plot->getAttribute("_kind")); bool overwrite = plot->hasAttribute("_overwrite_kind_dependent_defaults") ? static_cast(plot->getAttribute("_overwrite_kind_dependent_defaults")) : false; @@ -14999,15 +15898,15 @@ static void applyCentralRegionDefaults(const std::shared_ptr ¢ static void applyPlotDefaults(const std::shared_ptr &plot) { - if (!plot->hasAttribute("kind")) plot->setAttribute("kind", PLOT_DEFAULT_KIND); + if (!plot->hasAttribute("_kind")) plot->setAttribute("_kind", PLOT_DEFAULT_KIND); if (!plot->hasAttribute("keep_aspect_ratio")) plot->setAttribute("keep_aspect_ratio", PLOT_DEFAULT_KEEP_ASPECT_RATIO); if (!plot->hasAttribute("only_quadratic_aspect_ratio")) plot->setAttribute("only_quadratic_aspect_ratio", PLOT_DEFAULT_ONLY_QUADRATIC_ASPECT_RATIO); - if (!plot->hasAttribute("plot_x_min")) plot->setAttribute("plot_x_min", PLOT_DEFAULT_SUBPLOT_MIN_X); - if (!plot->hasAttribute("plot_x_max")) plot->setAttribute("plot_x_max", PLOT_DEFAULT_SUBPLOT_MAX_X); - if (!plot->hasAttribute("plot_y_min")) plot->setAttribute("plot_y_min", PLOT_DEFAULT_SUBPLOT_MIN_Y); - if (!plot->hasAttribute("plot_y_max")) plot->setAttribute("plot_y_max", PLOT_DEFAULT_SUBPLOT_MAX_Y); - auto kind = static_cast(plot->getAttribute("kind")); + if (!plot->hasAttribute("plot_x_min")) plot->setAttribute("plot_x_min", PLOT_DEFAULT_PLOT_MIN_X); + if (!plot->hasAttribute("plot_x_max")) plot->setAttribute("plot_x_max", PLOT_DEFAULT_PLOT_MAX_X); + if (!plot->hasAttribute("plot_y_min")) plot->setAttribute("plot_y_min", PLOT_DEFAULT_PLOT_MIN_Y); + if (!plot->hasAttribute("plot_y_max")) plot->setAttribute("plot_y_max", PLOT_DEFAULT_PLOT_MAX_Y); + auto kind = static_cast(plot->getAttribute("_kind")); bool overwrite = plot->hasAttribute("_overwrite_kind_dependent_defaults") ? static_cast(plot->getAttribute("_overwrite_kind_dependent_defaults")) : false; @@ -15030,7 +15929,14 @@ static void applyPlotDefaults(const std::shared_ptr &plot) } else { - plot->setAttribute("adjust_y_lim", (plot->hasAttribute("y_lim_min") ? 0 : PLOT_DEFAULT_ADJUST_YLIM)); + if (polar_kinds.count(kind) > 0 || kind == "pie") + { + plot->setAttribute("adjust_y_lim", PLOT_DEFAULT_ADJUST_YLIM); + } + else + { + plot->setAttribute("adjust_y_lim", (plot->hasAttribute("y_lim_min") ? 0 : PLOT_DEFAULT_ADJUST_YLIM)); + } } } if (!plot->hasAttribute("adjust_z_lim") || overwrite) @@ -15069,10 +15975,7 @@ static void applyPlotDefaultsHelper(const std::shared_ptr &element { for (const auto &child : element->children()) { - if (child->localName() == "plot") - { - applyPlotDefaults(child); - } + if (child->localName() == "plot") applyPlotDefaults(child); } } if (element->localName() == "layout_grid") @@ -15086,8 +15989,8 @@ static void applyPlotDefaultsHelper(const std::shared_ptr &element static void applyRootDefaults(const std::shared_ptr &root) { - if (!root->hasAttribute("clear_ws")) root->setAttribute("clear_ws", PLOT_DEFAULT_CLEAR); - if (!root->hasAttribute("update_ws")) root->setAttribute("update_ws", PLOT_DEFAULT_UPDATE); + if (!root->hasAttribute("_clear_ws")) root->setAttribute("_clear_ws", PLOT_DEFAULT_CLEAR); + if (!root->hasAttribute("_update_ws")) root->setAttribute("_update_ws", PLOT_DEFAULT_UPDATE); if (!root->hasAttribute("_modified")) root->setAttribute("_modified", false); for (const auto &figure : root->children()) @@ -15109,20 +16012,13 @@ static void applyRootDefaults(const std::shared_ptr &root) for (const auto &child : figure->children()) { - if (child->localName() == "plot") - { - applyPlotDefaults(child); - } - if (child->localName() == "layout_grid") - { - applyPlotDefaultsHelper(child); - } + if (child->localName() == "plot") applyPlotDefaults(child); + if (child->localName() == "layout_grid") applyPlotDefaultsHelper(child); } } } } - std::shared_ptr GRM::Render::getRenderContext() { return this->context; @@ -15215,14 +16111,14 @@ void GRM::Render::render() GRM::SerializerOptions::InternalAttributesFormat::Plain}) << "\n"; } - if (static_cast(root->getAttribute("clear_ws"))) gr_clearws(); + if (static_cast(root->getAttribute("_clear_ws"))) gr_clearws(); root->setAttribute("_modified", true); finalizeGrid(active_figure); renderHelper(root, this->context); renderZQueue(this->context); root->setAttribute("_modified", false); // reset the modified flag, cause all updates are made if (getenv("GRDISPLAY") && strcmp(getenv("GRDISPLAY"), "edit") == 0) missingBboxCalculator(root, this->context); - if (root->hasAttribute("update_ws") && static_cast(root->getAttribute("update_ws"))) gr_updatews(); + if (root->hasAttribute("_update_ws") && static_cast(root->getAttribute("_update_ws"))) gr_updatews(); // needed when series_line is changed to series_scatter for example if (getenv("GRDISPLAY") && strcmp(getenv("GRDISPLAY"), "edit") == 0) { @@ -15274,7 +16170,7 @@ GRM::Render::Render() /*! * This is the constructor for GRM::Render */ - this->context = std::shared_ptr(new Context()); + this->context = std::make_shared(); } std::shared_ptr GRM::Render::getContext() @@ -15300,10 +16196,10 @@ std::vector GRM::Render::getDefaultAndTooltip(const std::shared_ptr std::vector{"None", "A context reference for the absolute upward errors"}}, {std::string("absolute_upwards_flt"), std::vector{"None", "The flat absolute upward error. It gets applied at all error points"}}, - {std::string("absolute_height"), std::vector{"None", "Absolut height in percent of window"}}, - {std::string("absolute_height_pxl"), std::vector{"None", "Absolut height in pixel"}}, - {std::string("absolute_width"), std::vector{"None", "Absolut width in percent of window"}}, - {std::string("absolute_width_pxl"), std::vector{"None", "Absolut width in pixel"}}, + {std::string("absolute_height"), std::vector{"None", "Absolute height in percent of window"}}, + {std::string("absolute_height_pxl"), std::vector{"None", "Absolute height in pixel"}}, + {std::string("absolute_width"), std::vector{"None", "Absolute width in percent of window"}}, + {std::string("absolute_width_pxl"), std::vector{"None", "Absolute width in pixel"}}, {std::string("accelerate"), std::vector{"1", "Sets if the GR3 or the GR surface should be used"}}, {std::string("active"), std::vector{"None", "Sets if the element is shown/active"}}, {std::string("adjust_x_lim"), std::vector{"1", "Sets if the x-limits gets adjusted"}}, @@ -15312,8 +16208,9 @@ std::vector GRM::Render::getDefaultAndTooltip(const std::shared_ptr {std::string("aspect_ratio"), std::vector{"None", "Aspect ratio"}}, {std::string("algorithm"), std::vector{"sum", "The used algorithm for the calculation"}}, {std::string("ambient"), std::vector{"0.2", "The ambient light"}}, - {std::string("angle_ticks"), - std::vector{"None", "The interval between minor tick marks on the angle-axis"}}, + {std::string("angle_label"), std::vector{"", "The angle labels for the theta axes"}}, + {std::string("angle_line_num"), std::vector{"8", "The number of angle lines"}}, + {std::string("arc_label"), std::vector{"", "The arc labels for the rho axes"}}, {std::string("axis_type"), std::vector{"None", "Defines if the axis is getting used for x or y"}}, {std::string("bar_width"), std::vector{"None", "The width of all bars"}}, {std::string("bin_counts"), std::vector{"None", "References the bin-counts stored in the context"}}, @@ -15335,6 +16232,11 @@ std::vector GRM::Render::getDefaultAndTooltip(const std::shared_ptr {std::string("classes"), std::vector{"None", "References the histogram classes stored in the context"}}, {std::string("clip_transformation"), std::vector{"None", "The transformation for clipping"}}, + {std::string("clip_negative"), + std::vector{"False", "Defines if negative radii get clipped, otherwise they will be mirrored"}}, + {std::string("clip_region"), + std::vector{ + "0", "Defines whether a quadratic(0) or elliptic(1) clip region will be used to clip the displayed plot"}}, {std::string("color_ind"), std::vector{"None", "The index of the used color"}}, {std::string("color_ind_values"), std::vector{"None", "References the color-values stored in the context in index format"}}, @@ -15367,10 +16269,8 @@ std::vector GRM::Render::getDefaultAndTooltip(const std::shared_ptr {std::string("error_bar_x"), std::vector{"None", "The x-value for the error"}}, {std::string("error_bar_y_max"), std::vector{"None", "The ending y-value for the error"}}, {std::string("error_bar_y_min"), std::vector{"None", "The beginning y-value for the error"}}, - {std::string("face_alpha"), std::vector{"None", "The alpha-value of the bins"}}, {std::string("fig_size_x"), std::vector{"None", "The figure x-size"}}, {std::string("fig_size_y"), std::vector{"None", "The figure y-size"}}, - {std::string("figure_id"), std::vector{"None", "The unique ID of the figure"}}, {std::string("fill_color_ind"), std::vector{"None", "Sets the index of the current fill color"}}, {std::string("fill_color_rgb"), std::vector{"None", "Color for the bars in rgb format"}}, {std::string("fill_int_style"), std::vector{"None", "Sets the index of the current fill style"}}, @@ -15396,6 +16296,8 @@ std::vector GRM::Render::getDefaultAndTooltip(const std::shared_ptr {std::string("is_mirrored"), std::vector{"None", "Defines if the tick is mirrored"}}, {std::string("isovalue"), std::vector{"0.5", "The used isovalue"}}, {std::string("keep_aspect_ratio"), std::vector{"1", "Sets if the aspect ratio is kept"}}, + {std::string("keep_radii_axes"), + std::vector{"False", "Defines if the radii-axes respect the ranges defined by y_lim_max/min"}}, {std::string("keep_window"), std::vector{"1", "Sets if the window will be inflicted by attribute changes"}}, {std::string("kind"), @@ -15450,19 +16352,19 @@ std::vector GRM::Render::getDefaultAndTooltip(const std::shared_ptr {std::string("orientation"), std::vector{"horizontal", "The orientation of the element"}}, {std::string("phi"), std::vector{"None", "References the phi-angles stored in the context"}}, {std::string("phi_dim"), std::vector{"None", "The dimension of the phi-angles"}}, - {std::string("phi_max"), std::vector{"None", "The ending phi-angle of the polar cellarray"}}, - {std::string("phi_min"), std::vector{"None", "The beginning phi-angle of the polar cellarray"}}, + {std::string("phi_max"), std::vector{"None", "The ending phi-angle of the polar cell array"}}, + {std::string("phi_min"), std::vector{"None", "The beginning phi-angle of the polar cell array"}}, {std::string("phi_flip"), std::vector{"0", "Sets if the phi-angles gets flipped"}}, {std::string("phi_lim_max"), std::vector{"None", "The ending phi-limit"}}, {std::string("phi_lim_min"), std::vector{"None", "The beginning phi-limit"}}, {std::string("plot_group"), std::vector{"None", "The plot group. Its used when more than one plot exists in the tree"}}, - {std::string("plot_id"), std::vector{"None", "The unique ID of the plot"}}, {std::string("plot_type"), std::vector{"None", "The type of the plot. It can be 2d, 3d or polar"}}, {std::string("plot_x_max"), std::vector{"None", "The ending x-coordinate of the plot"}}, {std::string("plot_x_min"), std::vector{"None", "The beginning x-coordinate of the plot"}}, {std::string("plot_y_max"), std::vector{"None", "The ending y-coordinate of the plot"}}, {std::string("plot_y_min"), std::vector{"None", "The beginning y-coordinate of the plot"}}, + {std::string("polar_with_pan"), std::vector{"False", "Defines if pan is allowed on polar plots"}}, {std::string("pos"), std::vector{ "None", "F.e. where the x-axis should be placed in relation to the y-axis (position on the y-axis)"}}, @@ -15492,7 +16394,6 @@ std::vector GRM::Render::getDefaultAndTooltip(const std::shared_ptr {std::string("relative_upwards_flt"), std::vector{"None", "The flat relative upward error. It gets applied at all error points"}}, {std::string("resample_method"), std::vector{"None", "The used resample method"}}, - {std::string("rings"), std::vector{"None", "The number of rings for polar coordinate systems"}}, {std::string("scale"), std::vector{"None", "The set scale"}}, {std::string("scientific_format"), std::vector{"None", "Set the used format which will determine how a specific text will be drawn. " @@ -15539,6 +16440,8 @@ std::vector GRM::Render::getDefaultAndTooltip(const std::shared_ptr "None", "The vertical text alignment. Defines where the vertical anker point of the test is placed."}}, {std::string("text_color_ind"), std::vector{"None", "The index of the text-color"}}, {std::string("text_encoding"), std::vector{"utf8", "The internal text encoding"}}, + {std::string("text_x0"), std::vector{"None", "The left x-position of the text"}}, + {std::string("text_y0"), std::vector{"None", "The left y-position of the text"}}, {std::string("theta"), std::vector{"None", "References the theta-values stored in the context"}}, {std::string("tick"), std::vector{"None", "The polar ticks or the interval between minor ticks"}}, {std::string("tick_label"), std::vector{"", "The label which will be placed next to the tick"}}, @@ -15707,8 +16610,10 @@ std::vector GRM::Render::getDefaultAndTooltip(const std::shared_ptr std::shared_ptr GRM::Render::createPlot(int plotId, const std::shared_ptr &ext_element) { std::shared_ptr plot = (ext_element == nullptr) ? createElement("plot") : ext_element; - plot->setAttribute("plot_id", "plot" + std::to_string(plotId)); + + plot->setAttribute("_plot_id", "plot" + std::to_string(plotId)); plot->setAttribute("plot_group", true); + return plot; } @@ -15716,6 +16621,7 @@ std::shared_ptr GRM::Render::createCentralRegion(const std::shared { std::shared_ptr central_region = (ext_element == nullptr) ? createElement("central_region") : ext_element; + return central_region; } @@ -15740,30 +16646,16 @@ GRM::Render::createPolymarker(const std::string &x_key, std::optional use_context = (ext_context == nullptr) ? context : ext_context; std::shared_ptr element = (ext_element == nullptr) ? createElement("polymarker") : ext_element; - if (x != std::nullopt) - { - (*use_context)[x_key] = x.value(); - } - element->setAttribute("x", x_key); - if (y != std::nullopt) - { - (*use_context)[y_key] = y.value(); - } + if (x != std::nullopt) (*use_context)[x_key] = x.value(); + element->setAttribute("x", x_key); + if (y != std::nullopt) (*use_context)[y_key] = y.value(); element->setAttribute("y", y_key); - if (marker_type != 0) - { - element->setAttribute("marker_type", marker_type); - } - if (marker_size != 0.0) - { - element->setAttribute("marker_size", marker_size); - } - if (marker_colorind != 0) - { - element->setAttribute("marker_color_ind", marker_colorind); - } + if (marker_type != 0) element->setAttribute("marker_type", marker_type); + if (marker_size != 0.0) element->setAttribute("marker_size", marker_size); + if (marker_colorind != 0) element->setAttribute("marker_color_ind", marker_colorind); + return element; } @@ -15772,20 +16664,13 @@ std::shared_ptr GRM::Render::createPolymarker(double x, double y, const std::shared_ptr &ext_element) { std::shared_ptr element = (ext_element == nullptr) ? createElement("polymarker") : ext_element; + element->setAttribute("x", x); element->setAttribute("y", y); - if (marker_type != 0) - { - element->setAttribute("marker_type", marker_type); - } - if (marker_size != 0.0) - { - element->setAttribute("marker_size", marker_size); - } - if (marker_colorind != 0) - { - element->setAttribute("marker_color_ind", marker_colorind); - } + if (marker_type != 0) element->setAttribute("marker_type", marker_type); + if (marker_size != 0.0) element->setAttribute("marker_size", marker_size); + if (marker_colorind != 0) element->setAttribute("marker_color_ind", marker_colorind); + return element; } @@ -15794,22 +16679,15 @@ std::shared_ptr GRM::Render::createPolyline(double x1, double x2, const std::shared_ptr &ext_element) { std::shared_ptr element = (ext_element == nullptr) ? createElement("polyline") : ext_element; + element->setAttribute("x1", x1); element->setAttribute("x2", x2); element->setAttribute("y1", y1); element->setAttribute("y2", y2); - if (line_type != 0) - { - element->setAttribute("line_type", line_type); - } - if (line_width != 0.0) - { - element->setAttribute("line_width", line_width); - } - if (line_colorind != 0) - { - element->setAttribute("line_color_ind", line_colorind); - } + if (line_type != 0) element->setAttribute("line_type", line_type); + if (line_width != 0.0) element->setAttribute("line_width", line_width); + if (line_colorind != 0) element->setAttribute("line_color_ind", line_colorind); + return element; } @@ -15834,28 +16712,16 @@ GRM::Render::createPolyline(const std::string &x_key, std::optional use_context = (ext_context == nullptr) ? context : ext_context; std::shared_ptr element = (ext_element == nullptr) ? createElement("polyline") : ext_element; - if (x != std::nullopt) - { - (*use_context)[x_key] = *x; - } + + if (x != std::nullopt) (*use_context)[x_key] = *x; element->setAttribute("x", x_key); - if (y != std::nullopt) - { - (*use_context)[y_key] = *y; - } + if (y != std::nullopt) (*use_context)[y_key] = *y; element->setAttribute("y", y_key); - if (line_type != 0) - { - element->setAttribute("line_type", line_type); - } - if (line_width != 0.0) - { - element->setAttribute("line_width", line_width); - } - if (line_colorind != 0) - { - element->setAttribute("line_color_ind", line_colorind); - } + + if (line_type != 0) element->setAttribute("line_type", line_type); + if (line_width != 0.0) element->setAttribute("line_width", line_width); + if (line_colorind != 0) element->setAttribute("line_color_ind", line_colorind); + return element; } @@ -15873,10 +16739,12 @@ std::shared_ptr GRM::Render::createText(double x, double y, const */ std::shared_ptr element = (ext_element == nullptr) ? createElement("text") : ext_element; + element->setAttribute("x", x); element->setAttribute("y", y); element->setAttribute("text", text); element->setAttribute("space", static_cast(space)); + return element; } @@ -15901,29 +16769,16 @@ GRM::Render::createFillArea(const std::string &x_key, std::optional use_context = (ext_context == nullptr) ? context : ext_context; std::shared_ptr element = (ext_element == nullptr) ? createElement("fill_area") : ext_element; - if (x != std::nullopt) - { - (*use_context)[x_key] = *x; - } + + if (x != std::nullopt) (*use_context)[x_key] = *x; element->setAttribute("x", x_key); - if (y != std::nullopt) - { - (*use_context)[y_key] = *y; - } + if (y != std::nullopt) (*use_context)[y_key] = *y; element->setAttribute("y", y_key); - if (fillintstyle != 0) - { - element->setAttribute("fill_int_style", fillintstyle); - } - if (fillstyle != 0) - { - element->setAttribute("fill_style", fillstyle); - } - if (fillcolorind != -1) - { - element->setAttribute("fill_color_ind", fillcolorind); - } + if (fillintstyle != 0) element->setAttribute("fill_int_style", fillintstyle); + if (fillstyle != 0) element->setAttribute("fill_style", fillstyle); + if (fillcolorind != -1) element->setAttribute("fill_color_ind", fillcolorind); + return element; } @@ -15935,7 +16790,7 @@ std::shared_ptr GRM::Render::createCellArray(double xmin, double x const std::shared_ptr &ext_element) { /*! - * This function can be used to create a CellArray GRM::Element + * This function can be used to create a cell_array GRM::Element * * \param[in] xmin A double value * \param[in] xmax A double value @@ -15954,7 +16809,8 @@ std::shared_ptr GRM::Render::createCellArray(double xmin, double x */ std::shared_ptr use_context = (ext_context == nullptr) ? context : ext_context; - std::shared_ptr element = (ext_element == nullptr) ? createElement("cellarray") : ext_element; + std::shared_ptr element = (ext_element == nullptr) ? createElement("cell_array") : ext_element; + element->setAttribute("x_min", xmin); element->setAttribute("x_max", xmax); element->setAttribute("y_min", ymin); @@ -15966,17 +16822,17 @@ std::shared_ptr GRM::Render::createCellArray(double xmin, double x element->setAttribute("num_col", ncol); element->setAttribute("num_row", nrow); element->setAttribute("color_ind_values", color_key); - if (color != std::nullopt) - { - (*use_context)[color_key] = *color; - } + if (color != std::nullopt) (*use_context)[color_key] = *color; + return element; } std::shared_ptr GRM::Render::createEmptyAxis(const std::shared_ptr &ext_element) { std::shared_ptr element = (ext_element == nullptr) ? createElement("axis") : ext_element; + if (!element->hasAttribute("_axis_id")) element->setAttribute("_axis_id", axis_id++); + return element; } @@ -15986,6 +16842,7 @@ std::shared_ptr GRM::Render::createAxis(double min_val, double max const std::shared_ptr &ext_element) { std::shared_ptr element = (ext_element == nullptr) ? createElement("axis") : ext_element; + element->setAttribute("min_value", min_val); element->setAttribute("max_value", max_val); element->setAttribute("tick", tick); @@ -15998,18 +16855,21 @@ std::shared_ptr GRM::Render::createAxis(double min_val, double max element->setAttribute("tick_orientation", tick_orientation); element->setAttribute("label_pos", label_pos); if (!element->hasAttribute("_axis_id")) element->setAttribute("_axis_id", axis_id++); + return element; } -std::shared_ptr GRM::Render::createTickGroup(int is_major, std::string tick_label, double value, +std::shared_ptr GRM::Render::createTickGroup(int is_major, const std::string &tick_label, double value, double width, const std::shared_ptr &ext_element) { std::shared_ptr element = (ext_element == nullptr) ? createElement("tick_group") : ext_element; + element->setAttribute("is_major", is_major); element->setAttribute("tick_label", tick_label); element->setAttribute("value", value); element->setAttribute("width", width); + return element; } @@ -16017,8 +16877,10 @@ std::shared_ptr GRM::Render::createTick(int is_major, double value const std::shared_ptr &ext_element) { std::shared_ptr element = (ext_element == nullptr) ? createElement("tick") : ext_element; + element->setAttribute("is_major", is_major); element->setAttribute("value", value); + return element; } @@ -16026,8 +16888,10 @@ std::shared_ptr GRM::Render::createGridLine(int is_major, double v const std::shared_ptr &ext_element) { std::shared_ptr element = (ext_element == nullptr) ? createElement("grid_line") : ext_element; + element->setAttribute("is_major", is_major); element->setAttribute("value", value); + return element; } @@ -16049,43 +16913,13 @@ std::shared_ptr GRM::Render::createLegend(const std::string &label */ std::shared_ptr element = (ext_element == nullptr) ? createElement("legend") : ext_element; - element->setAttribute("z_index", 4); std::shared_ptr use_context = (ext_context == nullptr) ? context : ext_context; + + element->setAttribute("z_index", 4); element->setAttribute("specs", specs_key); + if (specs != std::nullopt) (*use_context)[specs_key] = *specs; element->setAttribute("labels", labels_key); - - if (labels != std::nullopt) - { - (*use_context)[labels_key] = *labels; - } - if (specs != std::nullopt) - { - (*use_context)[specs_key] = *specs; - } - - return element; -} - -std::shared_ptr GRM::Render::createDrawPolarAxes(int angle_ticks, const std::string &kind, int phiflip, - const std::string &norm, double tick, double line_width, - const std::shared_ptr &ext_element) -{ - std::shared_ptr element = (ext_element == nullptr) ? createElement("polar_axes") : ext_element; - if (!norm.empty()) - { - element->setAttribute("norm", norm); - } - if (tick != 0.0) - { - element->setAttribute("tick", tick); - } - if (line_width != 0.0) - { - element->setAttribute("line_width", line_width); - } - element->setAttribute("angle_ticks", angle_ticks); - // todo should phiflip be passed when creating a polarAxesElement - // element->setAttribute("phi_flip", phiflip); + if (labels != std::nullopt) (*use_context)[labels_key] = *labels; return element; } @@ -16097,12 +16931,10 @@ std::shared_ptr GRM::Render::createPieLegend(const std::string &la { std::shared_ptr element = (ext_element == nullptr) ? createElement("legend") : ext_element; std::shared_ptr use_context = (ext_context == nullptr) ? context : ext_context; + element->setAttribute("labels", labels_key); + if (labels != std::nullopt) (*use_context)[labels_key] = *labels; - if (labels != std::nullopt) - { - (*use_context)[labels_key] = *labels; - } return element; } @@ -16111,6 +16943,7 @@ std::shared_ptr GRM::Render::createPieSegment(const double start_a const std::shared_ptr &ext_element) { std::shared_ptr element = (ext_element == nullptr) ? createElement("pie_segment") : ext_element; + element->setAttribute("start_angle", start_angle); element->setAttribute("end_angle", end_angle); element->setAttribute("text", text); @@ -16127,6 +16960,7 @@ std::shared_ptr GRM::Render::createBar(const double x1, const doub const std::shared_ptr &ext_element) { std::shared_ptr element = (ext_element == nullptr) ? createElement("bar") : ext_element; + element->setAttribute("x1", x1); element->setAttribute("x2", x2); element->setAttribute("y1", y1); @@ -16145,9 +16979,11 @@ std::shared_ptr GRM::Render::createBar(const double x1, const doub std::shared_ptr GRM::Render::createSeries(const std::string &name) { auto element = createElement("series_" + name); + element->setAttribute("kind", name); element->setAttribute("_update_required", false); element->setAttribute("_delete_children", 0); + return element; } @@ -16174,6 +17010,7 @@ std::shared_ptr GRM::Render::createDrawImage(double xmin, double y */ std::shared_ptr use_context = (ext_context == nullptr) ? context : ext_context; std::shared_ptr element = (ext_element == nullptr) ? createElement("draw_image") : ext_element; + element->setAttribute("x_min", xmin); element->setAttribute("x_max", xmax); element->setAttribute("y_min", ymin); @@ -16182,10 +17019,8 @@ std::shared_ptr GRM::Render::createDrawImage(double xmin, double y element->setAttribute("height", height); element->setAttribute("model", model); element->setAttribute("data", data_key); - if (data != std::nullopt) - { - (*use_context)[data_key] = *data; - } + if (data != std::nullopt) (*use_context)[data_key] = *data; + return element; } @@ -16194,6 +17029,7 @@ std::shared_ptr GRM::Render::createDrawArc(double xmin, double xma const std::shared_ptr &ext_element) { std::shared_ptr element = (ext_element == nullptr) ? createElement("draw_arc") : ext_element; + element->setAttribute("x_min", xmin); element->setAttribute("x_max", xmax); element->setAttribute("y_min", ymin); @@ -16209,6 +17045,7 @@ std::shared_ptr GRM::Render::createFillArc(double xmin, double xma const std::shared_ptr &ext_element) { std::shared_ptr element = (ext_element == nullptr) ? createElement("fill_arc") : ext_element; + element->setAttribute("x_min", xmin); element->setAttribute("x_max", xmax); element->setAttribute("y_min", ymin); @@ -16216,18 +17053,10 @@ std::shared_ptr GRM::Render::createFillArc(double xmin, double xma element->setAttribute("start_angle", a1); element->setAttribute("end_angle", a2); - if (fillintstyle != 0) - { - element->setAttribute("fill_int_style", fillintstyle); - } - if (fillstyle != 0) - { - element->setAttribute("fill_style", fillstyle); - } - if (fillcolorind != -1) - { - element->setAttribute("fill_color_ind", fillcolorind); - } + if (fillintstyle != 0) element->setAttribute("fill_int_style", fillintstyle); + if (fillstyle != 0) element->setAttribute("fill_style", fillstyle); + if (fillcolorind != -1) element->setAttribute("fill_color_ind", fillcolorind); + return element; } @@ -16235,6 +17064,7 @@ std::shared_ptr GRM::Render::createDrawRect(double xmin, double xm const std::shared_ptr &ext_element) { std::shared_ptr element = (ext_element == nullptr) ? createElement("draw_rect") : ext_element; + element->setAttribute("x_min", xmin); element->setAttribute("x_max", xmax); element->setAttribute("y_min", ymin); @@ -16248,23 +17078,15 @@ std::shared_ptr GRM::Render::createFillRect(double xmin, double xm const std::shared_ptr &ext_element) { std::shared_ptr element = (ext_element == nullptr) ? createElement("fill_rect") : ext_element; + element->setAttribute("x_min", xmin); element->setAttribute("x_max", xmax); element->setAttribute("y_min", ymin); element->setAttribute("y_max", ymax); - if (fillintstyle != 0) - { - element->setAttribute("fill_int_style", fillintstyle); - } - if (fillstyle != 0) - { - element->setAttribute("fill_style", fillstyle); - } - if (fillcolorind != -1) - { - element->setAttribute("fill_color_ind", fillcolorind); - } + if (fillintstyle != 0) element->setAttribute("fill_int_style", fillintstyle); + if (fillstyle != 0) element->setAttribute("fill_style", fillstyle); + if (fillcolorind != -1) element->setAttribute("fill_color_ind", fillcolorind); return element; } @@ -16281,28 +17103,17 @@ std::shared_ptr GRM::Render::createQuiver(const std::string &x_key */ std::shared_ptr use_context = (ext_context == nullptr) ? context : ext_context; auto element = createSeries("quiver"); + element->setAttribute("x", x_key); element->setAttribute("y", y_key); element->setAttribute("u", u_key); element->setAttribute("v", v_key); element->setAttribute("color_ind", color); - if (x != std::nullopt) - { - (*use_context)[x_key] = *x; - } - if (y != std::nullopt) - { - (*use_context)[y_key] = *y; - } - if (u != std::nullopt) - { - (*use_context)[u_key] = *u; - } - if (v != std::nullopt) - { - (*use_context)[v_key] = *v; - } + if (x != std::nullopt) (*use_context)[x_key] = *x; + if (y != std::nullopt) (*use_context)[y_key] = *y; + if (u != std::nullopt) (*use_context)[u_key] = *u; + if (v != std::nullopt) (*use_context)[v_key] = *v; return element; } @@ -16316,17 +17127,12 @@ std::shared_ptr GRM::Render::createHexbin(const std::string &x_key */ std::shared_ptr use_context = (ext_context == nullptr) ? context : ext_context; auto element = createSeries("hexbin"); + element->setAttribute("x", x_key); element->setAttribute("y", y_key); - if (x != std::nullopt) - { - (*use_context)[x_key] = *x; - } - if (y != std::nullopt) - { - (*use_context)[y_key] = *y; - } + if (x != std::nullopt) (*use_context)[x_key] = *x; + if (y != std::nullopt) (*use_context)[y_key] = *y; return element; } @@ -16340,6 +17146,7 @@ std::shared_ptr GRM::Render::createColorbar(unsigned int colors, */ std::shared_ptr use_context = (ext_context == nullptr) ? context : ext_context; std::shared_ptr element = (ext_element == nullptr) ? createElement("colorbar") : ext_element; + element->setAttribute("color_ind", static_cast(colors)); element->setAttribute("_update_required", false); element->setAttribute("_delete_children", 0); @@ -16416,7 +17223,8 @@ std::shared_ptr GRM::Render::createPolarCellArray( */ std::shared_ptr use_context = (ext_context == nullptr) ? context : ext_context; - std::shared_ptr element = (ext_element == nullptr) ? createElement("polarcellarray") : ext_element; + std::shared_ptr element = (ext_element == nullptr) ? createElement("polar_cell_array") : ext_element; + element->setAttribute("x_org", x_org); element->setAttribute("y_org", y_org); element->setAttribute("phi_min", phimin); @@ -16430,10 +17238,8 @@ std::shared_ptr GRM::Render::createPolarCellArray( element->setAttribute("num_col", ncol); element->setAttribute("num_row", nrow); element->setAttribute("color_ind_values", color_key); - if (color != std::nullopt) - { - (*use_context)[color_key] = *color; - } + if (color != std::nullopt) (*use_context)[color_key] = *color; + return element; } @@ -16508,7 +17314,8 @@ std::shared_ptr GRM::Render::createNonUniformPolarCellArray( std::shared_ptr use_context = (ext_context == nullptr) ? context : ext_context; std::shared_ptr element = - (ext_element == nullptr) ? createElement("nonuniform_polarcellarray") : ext_element; + (ext_element == nullptr) ? createElement("nonuniform_polar_cell_array") : ext_element; + element->setAttribute("x_org", x_org); element->setAttribute("y_org", y_org); element->setAttribute("r", r_key); @@ -16520,18 +17327,11 @@ std::shared_ptr GRM::Render::createNonUniformPolarCellArray( element->setAttribute("num_col", ncol); element->setAttribute("num_row", nrow); element->setAttribute("color_ind_values", color_key); - if (color != std::nullopt) - { - (*use_context)[color_key] = *color; - } - if (phi != std::nullopt) - { - (*use_context)[phi_key] = *phi; - } - if (r != std::nullopt) - { - (*use_context)[r_key] = *r; - } + + if (color != std::nullopt) (*use_context)[color_key] = *color; + if (phi != std::nullopt) (*use_context)[phi_key] = *phi; + if (r != std::nullopt) (*use_context)[r_key] = *r; + return element; } @@ -16542,10 +17342,12 @@ std::shared_ptr GRM::Render::createNonUniformCellArray( const std::shared_ptr &ext_context, const std::shared_ptr &ext_element) { /*! - * This function can be used to create a non uniform cell array GRM::Element + * This function can be used to create a nonuniform cell array GRM::Element */ std::shared_ptr use_context = (ext_context == nullptr) ? context : ext_context; - std::shared_ptr element = (ext_element == nullptr) ? createElement("nonuniformcellarray") : ext_element; + std::shared_ptr element = + (ext_element == nullptr) ? createElement("nonuniform_cell_array") : ext_element; + element->setAttribute("x", x_key); element->setAttribute("y", y_key); element->setAttribute("color_ind_values", color_key); @@ -16556,18 +17358,9 @@ std::shared_ptr GRM::Render::createNonUniformCellArray( element->setAttribute("num_col", ncol); element->setAttribute("num_row", nrow); - if (x != std::nullopt) - { - (*use_context)[x_key] = *x; - } - if (y != std::nullopt) - { - (*use_context)[y_key] = *y; - } - if (color != std::nullopt) - { - (*use_context)[color_key] = *color; - } + if (x != std::nullopt) (*use_context)[x_key] = *x; + if (y != std::nullopt) (*use_context)[y_key] = *y; + if (color != std::nullopt) (*use_context)[color_key] = *color; return element; } @@ -16577,6 +17370,7 @@ std::shared_ptr GRM::Render::createGrid3d(double x_tick, double y_ int z_major, const std::shared_ptr &ext_element) { std::shared_ptr element = (ext_element == nullptr) ? createElement("grid_3d") : ext_element; + element->setAttribute("x_tick", x_tick); element->setAttribute("y_tick", y_tick); element->setAttribute("z_tick", z_tick); @@ -16586,6 +17380,7 @@ std::shared_ptr GRM::Render::createGrid3d(double x_tick, double y_ element->setAttribute("x_major", x_major); element->setAttribute("y_major", y_major); element->setAttribute("z_major", z_major); + return element; } @@ -16593,18 +17388,11 @@ std::shared_ptr GRM::Render::createEmptyGrid3d(bool x_grid, bool y const std::shared_ptr &ext_element) { auto element = (ext_element == nullptr) ? createElement("grid_3d") : ext_element; - if (!x_grid) - { - element->setAttribute("x_tick", 0); - } - if (!y_grid) - { - element->setAttribute("y_tick", 0); - } - if (!z_grid) - { - element->setAttribute("z_tick", 0); - } + + if (!x_grid) element->setAttribute("x_tick", false); + if (!y_grid) element->setAttribute("y_tick", false); + if (!z_grid) element->setAttribute("z_tick", false); + return element; } @@ -16614,6 +17402,7 @@ std::shared_ptr GRM::Render::createAxes3d(double x_tick, double y_ const std::shared_ptr &ext_element) { std::shared_ptr element = (ext_element == nullptr) ? createElement("axes_3d") : ext_element; + element->setAttribute("x_tick", x_tick); element->setAttribute("y_tick", y_tick); element->setAttribute("z_tick", z_tick); @@ -16624,6 +17413,7 @@ std::shared_ptr GRM::Render::createAxes3d(double x_tick, double y_ element->setAttribute("major_y", major_y); element->setAttribute("major_z", major_z); element->setAttribute("tick_orientation", tick_orientation); + return element; } @@ -16631,7 +17421,9 @@ std::shared_ptr GRM::Render::createEmptyAxes3d(int tick_orientatio const std::shared_ptr &ext_element) { std::shared_ptr element = (ext_element == nullptr) ? createElement("axes_3d") : ext_element; + element->setAttribute("tick_orientation", tick_orientation); + return element; } @@ -16643,22 +17435,14 @@ GRM::Render::createPolyline3d(const std::string &x_key, std::optional use_context = (ext_context == nullptr) ? context : ext_context; std::shared_ptr element = (ext_element == nullptr) ? createElement("polyline_3d") : ext_element; + element->setAttribute("x", x_key); element->setAttribute("y", y_key); element->setAttribute("z", z_key); - if (x != std::nullopt) - { - (*use_context)[x_key] = *x; - } - if (y != std::nullopt) - { - (*use_context)[y_key] = *y; - } - if (z != std::nullopt) - { - (*use_context)[z_key] = *z; - } + if (x != std::nullopt) (*use_context)[x_key] = *x; + if (y != std::nullopt) (*use_context)[y_key] = *y; + if (z != std::nullopt) (*use_context)[z_key] = *z; return element; } @@ -16670,22 +17454,14 @@ std::shared_ptr GRM::Render::createPolymarker3d( { std::shared_ptr use_context = (ext_context == nullptr) ? context : ext_context; std::shared_ptr element = (ext_element == nullptr) ? createElement("polymarker_3d") : ext_element; + element->setAttribute("x", x_key); element->setAttribute("y", y_key); element->setAttribute("z", z_key); - if (x != std::nullopt) - { - (*use_context)[x_key] = *x; - } - if (y != std::nullopt) - { - (*use_context)[y_key] = *y; - } - if (z != std::nullopt) - { - (*use_context)[z_key] = *z; - } + if (x != std::nullopt) (*use_context)[x_key] = *x; + if (y != std::nullopt) (*use_context)[y_key] = *y; + if (z != std::nullopt) (*use_context)[z_key] = *z; return element; } @@ -16698,22 +17474,14 @@ GRM::Render::createTriSurface(const std::string &px_key, std::optional use_context = (ext_context == nullptr) ? context : ext_context; auto element = createSeries("trisurface"); + element->setAttribute("x", px_key); element->setAttribute("y", py_key); element->setAttribute("z", pz_key); - if (px != std::nullopt) - { - (*use_context)[px_key] = *px; - } - if (py != std::nullopt) - { - (*use_context)[py_key] = *py; - } - if (pz != std::nullopt) - { - (*use_context)[pz_key] = *pz; - } + if (px != std::nullopt) (*use_context)[px_key] = *px; + if (py != std::nullopt) (*use_context)[py_key] = *py; + if (pz != std::nullopt) (*use_context)[pz_key] = *pz; return element; } @@ -16738,18 +17506,18 @@ std::shared_ptr GRM::Render::createDrawGraphics(const std::string std::shared_ptr use_context = (ext_context == nullptr) ? context : ext_context; std::shared_ptr element = (ext_element == nullptr) ? createElement("draw_graphics") : ext_element; - if (data != std::nullopt) - { - (*use_context)[data_key] = *data; - } element->setAttribute("data", data_key); + if (data != std::nullopt) (*use_context)[data_key] = *data; + return element; } std::shared_ptr GRM::Render::createIsoSurfaceRenderElement(int drawable_type) { auto element = createElement("isosurface_render"); + element->setAttribute("drawable_type", drawable_type); + return element; } @@ -16757,42 +17525,42 @@ std::shared_ptr GRM::Render::createLayoutGrid(const grm::Grid &gri { auto element = createElement("layout_grid"); - if (grid.absHeight != -1) element->setAttribute("absolute_height", grid.absHeight); - if (grid.absWidth != -1) element->setAttribute("absolute_width", grid.absWidth); - if (grid.absHeightPxl != -1) element->setAttribute("absolute_height_pxl", grid.absHeightPxl); - if (grid.absWidthPxl != -1) element->setAttribute("absolute_width_pxl", grid.absWidthPxl); - if (grid.relativeHeight != -1) element->setAttribute("relative_height", grid.relativeHeight); - if (grid.relativeWidth != -1) element->setAttribute("relative_width", grid.relativeWidth); - if (grid.aspectRatio != -1) element->setAttribute("aspect_ratio", grid.aspectRatio); - element->setAttribute("fit_parents_height", grid.fitParentsHeight); - element->setAttribute("fit_parents_width", grid.fitParentsWidth); + if (grid.abs_height != -1) element->setAttribute("absolute_height", grid.abs_height); + if (grid.abs_width != -1) element->setAttribute("absolute_width", grid.abs_width); + if (grid.abs_height_pxl != -1) element->setAttribute("absolute_height_pxl", grid.abs_height_pxl); + if (grid.abs_width_pxl != -1) element->setAttribute("absolute_width_pxl", grid.abs_width_pxl); + if (grid.relative_height != -1) element->setAttribute("relative_height", grid.relative_height); + if (grid.relative_width != -1) element->setAttribute("relative_width", grid.relative_width); + if (grid.aspect_ratio != -1) element->setAttribute("aspect_ratio", grid.aspect_ratio); + element->setAttribute("fit_parents_height", grid.fit_parents_height); + element->setAttribute("fit_parents_width", grid.fit_parents_width); element->setAttribute("num_row", grid.getNRows()); element->setAttribute("num_col", grid.getNCols()); return element; } -std::shared_ptr GRM::Render::createLayoutGridElement(const grm::GridElement &gridElement, +std::shared_ptr GRM::Render::createLayoutGridElement(const grm::GridElement &grid_element, const grm::Slice &slice) { auto element = createElement("layout_grid_element"); - if (gridElement.absHeight != -1) element->setAttribute("absolute_height", gridElement.absHeight); - if (gridElement.absWidth != -1) element->setAttribute("absolute_width", gridElement.absWidth); - if (gridElement.absHeightPxl != -1) element->setAttribute("absolute_height_pxl", gridElement.absHeightPxl); - if (gridElement.absWidthPxl != -1) element->setAttribute("absolute_width_pxl", gridElement.absWidthPxl); - element->setAttribute("fit_parents_height", gridElement.fitParentsHeight); - element->setAttribute("fit_parents_width", gridElement.fitParentsWidth); - if (gridElement.relativeHeight != -1) element->setAttribute("relative_height", gridElement.relativeHeight); - if (gridElement.relativeWidth != -1) element->setAttribute("relative_width", gridElement.relativeWidth); - if (gridElement.aspectRatio != -1) element->setAttribute("aspect_ratio", gridElement.aspectRatio); - element->setAttribute("start_row", slice.rowStart); - element->setAttribute("stop_row", slice.rowStop); - element->setAttribute("start_col", slice.colStart); - element->setAttribute("stop_col", slice.colStop); - - double *subplot = gridElement.subplot; - GRM::Render::setSubplot(element, subplot[0], subplot[1], subplot[2], subplot[3]); + if (grid_element.abs_height != -1) element->setAttribute("absolute_height", grid_element.abs_height); + if (grid_element.abs_width != -1) element->setAttribute("absolute_width", grid_element.abs_width); + if (grid_element.abs_height_pxl != -1) element->setAttribute("absolute_height_pxl", grid_element.abs_height_pxl); + if (grid_element.abs_width_pxl != -1) element->setAttribute("absolute_width_pxl", grid_element.abs_width_pxl); + element->setAttribute("fit_parents_height", grid_element.fit_parents_height); + element->setAttribute("fit_parents_width", grid_element.fit_parents_width); + if (grid_element.relative_height != -1) element->setAttribute("relative_height", grid_element.relative_height); + if (grid_element.relative_width != -1) element->setAttribute("relative_width", grid_element.relative_width); + if (grid_element.aspect_ratio != -1) element->setAttribute("aspect_ratio", grid_element.aspect_ratio); + element->setAttribute("start_row", slice.row_start); + element->setAttribute("stop_row", slice.row_stop); + element->setAttribute("start_col", slice.col_start); + element->setAttribute("stop_col", slice.col_stop); + + double *plot = grid_element.plot; + GRM::Render::setPlot(element, plot[0], plot[1], plot[2], plot[3]); return element; } @@ -16800,10 +17568,12 @@ std::shared_ptr GRM::Render::createLayoutGridElement(const grm::Gr std::shared_ptr GRM::Render::createPanzoom(double x, double y, double xzoom, double yzoom) { auto element = createElement("panzoom"); + element->setAttribute("x", x); element->setAttribute("y", y); element->setAttribute("x_zoom", xzoom); element->setAttribute("y_zoom", yzoom); + return element; } @@ -16811,6 +17581,7 @@ std::shared_ptr GRM::Render::createPolarBar(double count, int clas const std::shared_ptr &ext_element) { std::shared_ptr element = (ext_element == nullptr) ? createElement("polar_bar") : ext_element; + element->setAttribute("count", count); element->setAttribute("class_nr", class_nr); @@ -16822,6 +17593,7 @@ std::shared_ptr GRM::Render::createErrorBar(double error_bar_x, do const std::shared_ptr &ext_element) { std::shared_ptr element = (ext_element == nullptr) ? createElement("error_bar") : ext_element; + element->setAttribute("error_bar_x", error_bar_x); element->setAttribute("error_bar_y_min", error_bar_y_min); element->setAttribute("error_bar_y_max", error_bar_y_max); @@ -16834,16 +17606,18 @@ std::shared_ptr GRM::Render::createIntegral(double int_lim_low, do const std::shared_ptr &ext_element) { std::shared_ptr element = (ext_element == nullptr) ? createElement("integral") : ext_element; + element->setAttribute("int_lim_low", int_lim_low); element->setAttribute("int_lim_high", int_lim_high); return element; } -std::shared_ptr GRM::Render::createSideRegion(std::string location, +std::shared_ptr GRM::Render::createSideRegion(const std::string &location, const std::shared_ptr &ext_element) { std::shared_ptr element = (ext_element == nullptr) ? createElement("side_region") : ext_element; + element->setAttribute("location", location); return element; @@ -16863,9 +17637,56 @@ std::shared_ptr GRM::Render::createSidePlotRegion(const std::share return element; } +std::shared_ptr GRM::Render::createRhoAxes(const std::shared_ptr &ext_element) +{ + std::shared_ptr element = (ext_element == nullptr) ? createElement("rho_axes") : ext_element; + + return element; +} + +std::shared_ptr GRM::Render::createThetaAxes(const std::shared_ptr &ext_element) +{ + std::shared_ptr element = (ext_element == nullptr) ? createElement("theta_axes") : ext_element; + + return element; +} + +std::shared_ptr GRM::Render::createAngleLine(double x, double y, const std::string &angle_label, + const std::shared_ptr &ext_element) +{ + std::shared_ptr element = (ext_element == nullptr) ? createElement("angle_line") : ext_element; + + element->setAttribute("angle_label", angle_label); + element->setAttribute("x", x); + element->setAttribute("y", y); + + return element; +} + +std::shared_ptr GRM::Render::createArcGridLine(double value, + const std::shared_ptr &ext_element) +{ + std::shared_ptr element = (ext_element == nullptr) ? createElement("arc_grid_line") : ext_element; + + element->setAttribute("value", value); + + return element; +} + /* ~~~~~~~~~~~~~~~~~~~~~~~~~ modifier functions~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +void GRM::Render::setClipRegion(const std::shared_ptr &element, int region) +{ + /*! + * This function can be used to set the clip region of a GRM::Element + * + * \param[in] element A GRM::Element + * \param[in] region The desired clip region + */ + element->setAttribute("clip_region", region); +} + void GRM::Render::setViewport(const std::shared_ptr &element, double xmin, double xmax, double ymin, double ymax) { @@ -16878,7 +17699,6 @@ void GRM::Render::setViewport(const std::shared_ptr &element, doub * \param[in] ymin TThe bottom vertical coordinate of the viewport (0 <= ymin < ymax) * \param[in] ymax The top vertical coordinate of the viewport (ymin < ymax <= 1) */ - element->setAttribute("viewport_x_min", xmin); element->setAttribute("viewport_x_max", xmax); element->setAttribute("viewport_y_min", ymin); @@ -16898,7 +17718,6 @@ void GRM::Render::setWSViewport(const std::shared_ptr &element, do * \param[in] ymin TThe bottom vertical coordinate of the viewport (0 <= ymin < ymax) * \param[in] ymax The top vertical coordinate of the viewport (ymin < ymax <= 1) */ - element->setAttribute("ws_viewport_x_min", xmin); element->setAttribute("ws_viewport_x_max", xmax); element->setAttribute("ws_viewport_y_min", ymin); @@ -16916,7 +17735,6 @@ void GRM::Render::setWindow(const std::shared_ptr &element, double xmin * \param[in] ymin The bottom vertical coordinate of the window (ymin < ymax) * \param[in] ymax The top vertical coordinate of the window (ymin < ymax) */ - element->setAttribute("window_x_min", xmin); element->setAttribute("window_x_max", xmax); element->setAttribute("window_y_min", ymin); @@ -16935,7 +17753,6 @@ void GRM::Render::setWSWindow(const std::shared_ptr &element, double xm * \param[in] ymin The bottom vertical coordinate of the window (ymin < ymax) * \param[in] ymax The top vertical coordinate of the window (ymin < ymax) */ - element->setAttribute("ws_window_x_min", xmin); element->setAttribute("ws_window_x_max", xmax); element->setAttribute("ws_window_y_min", ymin); @@ -16966,10 +17783,7 @@ void GRM::Render::setMarkerType(const std::shared_ptr &element, const s * but an external GRM::Context can be used */ std::shared_ptr use_context = (ext_context == nullptr) ? context : ext_context; - if (types != std::nullopt) - { - (*use_context)[types_key] = *types; - } + if (types != std::nullopt) (*use_context)[types_key] = *types; element->setAttribute("marker_types", types_key); } @@ -16998,10 +17812,7 @@ void GRM::Render::setMarkerSize(const std::shared_ptr &element, const s * but an external GRM::Context can be used */ std::shared_ptr use_context = (ext_context == nullptr) ? context : ext_context; - if (sizes != std::nullopt) - { - (*use_context)[sizes_key] = *sizes; - } + if (sizes != std::nullopt) (*use_context)[sizes_key] = *sizes; element->setAttribute("marker_sizes", sizes_key); } @@ -17030,10 +17841,7 @@ void GRM::Render::setMarkerColorInd(const std::shared_ptr &element, con * object but an external GRM::Context can be used */ std::shared_ptr use_context = (ext_context == nullptr) ? context : ext_context; - if (colorinds != std::nullopt) - { - (*use_context)[colorinds_key] = *colorinds; - } + if (colorinds != std::nullopt) (*use_context)[colorinds_key] = *colorinds; element->setAttribute("marker_color_indices", colorinds_key); } @@ -17082,10 +17890,7 @@ void GRM::Render::setLineWidth(const std::shared_ptr &element, const st * object but an external GRM::Context can be used */ std::shared_ptr use_context = (ext_context == nullptr) ? context : ext_context; - if (widths != std::nullopt) - { - (*use_context)[widths_key] = *widths; - } + if (widths != std::nullopt) (*use_context)[widths_key] = *widths; element->setAttribute("line_widths", widths_key); } @@ -17105,7 +17910,7 @@ void GRM::Render::setLineColorInd(const std::shared_ptr &element, const const std::shared_ptr &ext_context) { /*! - * This funciton can be used to set a vector of LineColorInds of a GRM::Element + * This function can be used to set a vector of LineColorInds of a GRM::Element * * \param[in] element A GRM::Element * \param[in] colorinds_key A string used as a key for storing the colorinds @@ -17114,10 +17919,7 @@ void GRM::Render::setLineColorInd(const std::shared_ptr &element, const * object but an external GRM::Context can be used */ std::shared_ptr use_context = (ext_context == nullptr) ? context : ext_context; - if (colorinds != std::nullopt) - { - (*use_context)[colorinds_key] = *colorinds; - } + if (colorinds != std::nullopt) (*use_context)[colorinds_key] = *colorinds; element->setAttribute("line_color_indices", colorinds_key); } @@ -17141,7 +17943,6 @@ void GRM::Render::setCharUp(const std::shared_ptr &element, double ux, * \param[in] ux X coordinate of the text up vector * \param[in] uy y coordinate of the text up vector */ - element->setAttribute("char_up_x", ux); element->setAttribute("char_up_y", uy); } @@ -17195,7 +17996,6 @@ void GRM::Render::setColorRep(const std::shared_ptr &element, int index * \param[in] green Green intensity in the range 0.0 to 1.0 * \param[in] blue Blue intensity in the range 0.0 to 1.0 */ - int precision = 255; int red_int = int(red * precision + 0.5), green_int = int(green * precision + 0.5), blue_int = int(blue * precision + 0.5); @@ -17240,7 +18040,6 @@ void GRM::Render::setFillStyle(const std::shared_ptr &element, int * \param[in] element A GRM::Element * \param[in] index The fill style index to be used */ - element->setAttribute("fill_style", index); } @@ -17269,7 +18068,6 @@ void GRM::Render::setWindow3d(const std::shared_ptr &element, doub * \param[in] zmin min z-value * \param[in] zmax max z-value */ - element->setAttribute("window_x_min", xmin); element->setAttribute("window_x_max", xmax); element->setAttribute("window_y_min", ymin); @@ -17289,7 +18087,6 @@ void GRM::Render::setSpace3d(const std::shared_ptr &element, doubl * \param[in] camera_distance: distance between the camera and the focus point (in arbitrary units, 0 or NaN for the * radius of the object's smallest bounding sphere) */ - element->setAttribute("space_3d_fov", fov); element->setAttribute("space_3d_camera_distance", camera_distance); } @@ -17305,7 +18102,6 @@ void GRM::Render::setSpace(const std::shared_ptr &element, double zmin, * \param[in] rotation * \param[in] tilt */ - element->setAttribute("space", true); element->setAttribute("space_z_min", zmin); element->setAttribute("space_z_max", zmax); @@ -17320,7 +18116,6 @@ void GRM::Render::setSelectSpecificXform(const std::shared_ptr &element * \param[in] element A GRM::Element * \param[in] transform Select a predefined transformation from world coordinates to normalized device coordinates. */ - element->setAttribute("select_specific_xform", transform); } @@ -17331,7 +18126,6 @@ void GRM::Render::setTextColorInd(const std::shared_ptr &element, * \param[in] element A GRM::Element * \param[in] index The color index */ - element->setAttribute("text_color_ind", index); } @@ -17393,7 +18187,6 @@ void GRM::Render::setResampleMethod(const std::shared_ptr &element * \param[in] element A GRM::Element * \param[in] resample The resample method */ - element->setAttribute("resample_method", resample); } @@ -17407,8 +18200,8 @@ void GRM::Render::setTextEncoding(const std::shared_ptr &element, int e element->setAttribute("text_encoding", encoding); } -void GRM::Render::setSubplot(const std::shared_ptr &element, double xmin, double xmax, double ymin, - double ymax) +void GRM::Render::setPlot(const std::shared_ptr &element, double xmin, double xmax, double ymin, + double ymax) { element->setAttribute("plot_x_min", xmin); element->setAttribute("plot_x_max", xmax); @@ -17511,6 +18304,7 @@ int GRM::Render::getAxisId() } /* ~~~~~~~~~~~~~~~~~~~~~~~~~ filter functions~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + static void setRanges(const std::shared_ptr &element, const std::shared_ptr &new_series) { if (element->hasAttribute("x_range_min")) @@ -17535,6 +18329,9 @@ void updateFilter(const std::shared_ptr &element, const std::strin std::vector error_bar{ "cap_x_max", "cap_x_min", "e_downwards", "e_upwards", "error_bar_x", "error_bar_y_max", "error_bar_y_min", }; + std::vector error_bars{ + "error_bar_style", + }; std::vector marginal_heatmap_plot{ "algorithm", "marginal_heatmap_kind", "x", "x_flip", "y", "y_flip", "z", }; @@ -17552,6 +18349,7 @@ void updateFilter(const std::shared_ptr &element, const std::strin "ind_edge_width", "indices", "inner_series", + "line_spec", "orientation", "rgb", "style", @@ -17572,7 +18370,7 @@ void updateFilter(const std::shared_ptr &element, const std::strin "y", }; std::vector series_hist{ - "bins", "fill_color_ind", "fill_color_rgb", "line_color_ind", "line_color_rgb", "orientation", + "bins", "fill_color_ind", "fill_color_rgb", "line_color_ind", "line_color_rgb", "line_spec", "orientation", }; std::vector series_imshow{ "data", "x", "y", "z", "z_dims", @@ -17586,8 +18384,8 @@ void updateFilter(const std::shared_ptr &element, const std::strin "x", "y", }; - std::vector series_nonuniformheatmap = series_heatmap; - std::vector series_nonuniformpolar_heatmap{ + std::vector series_nonuniform_heatmap = series_heatmap; + std::vector series_nonuniform_polar_heatmap{ "x", "y", "z", "z_range_max", "z_range_min", }; std::vector series_pie{ @@ -17599,14 +18397,17 @@ void updateFilter(const std::shared_ptr &element, const std::strin "y", "z", }; - std::vector series_polar{ - "line_spec", "r_max", "r_min", "x", "y", - }; - std::vector series_polar_heatmap = series_nonuniformpolar_heatmap; + std::vector series_polar_heatmap = series_nonuniform_polar_heatmap; std::vector series_polar_histogram{ - "bin_counts", "bin_edges", "bin_width", "bin_widths", "classes", "draw_edges", - "face_alpha", "num_bins", "norm", "r_max", "r_min", "stairs", - "theta", "tick", "total", "transparency", "x_colormap", "y_colormap", + "bin_counts", "bin_edges", "bin_width", "bin_widths", "classes", "draw_edges", + "keep_radii_axes", "num_bins", "norm", "r_max", "r_min", "stairs", + "theta", "tick", "total", "transparency", "x_colormap", "y_colormap", + }; + std::vector series_polar_line{ + "clip_negative", "line_spec", "r_max", "r_min", "x", "y", + }; + std::vector series_polar_scatter{ + "clip_negative", "line_spec", "r_max", "r_min", "x", "y", }; std::vector series_quiver{ "color_ind", "u", "v", "x", "y", @@ -17624,13 +18425,10 @@ void updateFilter(const std::shared_ptr &element, const std::strin "transformation", "x", "x_bins", "y", "y_bins", }; std::vector series_stairs{ - "orientation", "step_where", "x", "y", "z", + "line_spec", "orientation", "step_where", "x", "y", "z", }; std::vector series_stem{ - "orientation", - "x", - "y", - "y_range_min", + "line_spec", "orientation", "x", "y", "y_range_min", }; std::vector series_surface{ "accelerate", @@ -17657,11 +18455,12 @@ void updateFilter(const std::shared_ptr &element, const std::strin "y", "z", }; - std::vector coordinate_system_element{"angle_ticks", "normalization", "phi_flip", "x_grid", - "y_grid", "z_grid", "plot_type"}; + std::vector coordinate_system_element{"normalization", "phi_flip", "x_grid", + "y_grid", "z_grid", "plot_type"}; static std::map> element_names{ {std::string("bar"), bar}, {std::string("error_bar"), error_bar}, + {std::string("error_bars"), error_bars}, {std::string("polar_bar"), polar_bar}, {std::string("coordinate_system"), coordinate_system_element}, {std::string("marginal_heatmap_plot"), marginal_heatmap_plot}, @@ -17674,13 +18473,14 @@ void updateFilter(const std::shared_ptr &element, const std::strin {std::string("series_imshow"), series_imshow}, {std::string("series_isosurface"), series_isosurface}, {std::string("series_line"), series_line}, - {std::string("series_nonuniformheatmap"), series_nonuniformheatmap}, - {std::string("series_nonuniformpolar_heatmap"), series_nonuniformpolar_heatmap}, + {std::string("series_nonuniform_heatmap"), series_nonuniform_heatmap}, + {std::string("series_nonuniform_polar_heatmap"), series_nonuniform_polar_heatmap}, {std::string("series_pie"), series_pie}, {std::string("series_plot3"), series_plot3}, - {std::string("series_polar"), series_polar}, {std::string("series_polar_heatmap"), series_polar_heatmap}, {std::string("series_polar_histogram"), series_polar_histogram}, + {std::string("series_polar_line"), series_polar_line}, + {std::string("series_polar_scatter"), series_polar_scatter}, {std::string("series_quiver"), series_quiver}, {std::string("series_scatter"), series_scatter}, {std::string("series_scatter3"), series_scatter3}, @@ -17723,6 +18523,7 @@ void updateFilter(const std::shared_ptr &element, const std::strin std::vector plot3_group = {"plot3", "scatter", "scatter3", "tricontour", "trisurface"}; std::vector barplot_group = {"barplot", "hist", "stem", "stairs"}; std::vector hexbin_group = {"hexbin", "shade"}; + std::vector polar_line_group = {"polar_line", "polar_scatter"}; std::shared_ptr new_element = nullptr; std::shared_ptr central_region, central_region_parent; @@ -17740,14 +18541,14 @@ void updateFilter(const std::shared_ptr &element, const std::strin } } + auto kind = static_cast(element->getAttribute("kind")); if (std::find(line_group.begin(), line_group.end(), value) != line_group.end() && - std::find(line_group.begin(), line_group.end(), - static_cast(element->getAttribute("kind"))) != line_group.end()) + std::find(line_group.begin(), line_group.end(), kind) != line_group.end()) { - auto new_series = global_render->createSeries(static_cast(element->getAttribute("kind"))); + auto new_series = global_render->createSeries(kind); new_element = new_series; element->parentElement()->insertBefore(new_series, element); - plot_parent->setAttribute("kind", static_cast(element->getAttribute("kind"))); + plot_parent->setAttribute("_kind", kind); new_series->setAttribute("x", element->getAttribute("x")); new_series->setAttribute("y", element->getAttribute("y")); new_series->setAttribute("_bbox_id", -1); @@ -17770,18 +18571,17 @@ void updateFilter(const std::shared_ptr &element, const std::strin } } else if (std::find(heatmap_group.begin(), heatmap_group.end(), value) != heatmap_group.end() && - std::find(heatmap_group.begin(), heatmap_group.end(), - static_cast(element->getAttribute("kind"))) != heatmap_group.end()) + std::find(heatmap_group.begin(), heatmap_group.end(), kind) != heatmap_group.end()) { std::shared_ptr new_series; - if (static_cast(element->getAttribute("kind")) == "marginal_heatmap") + if (kind == "marginal_heatmap") { new_series = global_render->createElement("marginal_heatmap_plot"); new_series->setAttribute("kind", "marginal_heatmap"); } else { - new_series = global_render->createSeries(static_cast(element->getAttribute("kind"))); + new_series = global_render->createSeries(kind); } new_element = new_series; if (value == "marginal_heatmap") @@ -17821,7 +18621,7 @@ void updateFilter(const std::shared_ptr &element, const std::strin element->parentElement()->insertBefore(central_region, first_side_region); central_region->append(new_series); } - else if (static_cast(element->getAttribute("kind")) == "marginal_heatmap") + else if (kind == "marginal_heatmap") { std::shared_ptr first_side_region = nullptr; // move the side_regions into the marginal_heatmap_plot @@ -17852,13 +18652,13 @@ void updateFilter(const std::shared_ptr &element, const std::strin { element->parentElement()->insertBefore(new_series, element); } - plot_parent->setAttribute("kind", static_cast(element->getAttribute("kind"))); + plot_parent->setAttribute("_kind", kind); new_series->setAttribute("x", element->getAttribute("x")); new_series->setAttribute("y", element->getAttribute("y")); new_series->setAttribute("z", element->getAttribute("z")); new_series->setAttribute("_bbox_id", -1); if (static_cast(central_region->getAttribute("keep_window"))) setRanges(element, new_series); - if (static_cast(element->getAttribute("kind")) == "imshow") + if (kind == "imshow") { auto context = global_render->getContext(); auto id = static_cast(global_root->getAttribute("_id")); @@ -17897,13 +18697,12 @@ void updateFilter(const std::shared_ptr &element, const std::strin new_series->setAttribute("_delete_children", 2); } else if (std::find(isosurface_group.begin(), isosurface_group.end(), value) != isosurface_group.end() && - std::find(isosurface_group.begin(), isosurface_group.end(), - static_cast(element->getAttribute("kind"))) != isosurface_group.end()) + std::find(isosurface_group.begin(), isosurface_group.end(), kind) != isosurface_group.end()) { - auto new_series = global_render->createSeries(static_cast(element->getAttribute("kind"))); + auto new_series = global_render->createSeries(kind); new_element = new_series; element->parentElement()->insertBefore(new_series, element); - plot_parent->setAttribute("kind", static_cast(element->getAttribute("kind"))); + plot_parent->setAttribute("_kind", kind); new_series->setAttribute("z", element->getAttribute("z")); new_series->setAttribute("z_dims", element->getAttribute("z_dims")); if (element->hasAttribute("d_min")) new_series->setAttribute("d_min", element->getAttribute("d_min")); @@ -17919,13 +18718,12 @@ void updateFilter(const std::shared_ptr &element, const std::strin new_series->setAttribute("_delete_children", 2); } else if (std::find(plot3_group.begin(), plot3_group.end(), value) != plot3_group.end() && - std::find(plot3_group.begin(), plot3_group.end(), - static_cast(element->getAttribute("kind"))) != plot3_group.end()) + std::find(plot3_group.begin(), plot3_group.end(), kind) != plot3_group.end()) { - auto new_series = global_render->createSeries(static_cast(element->getAttribute("kind"))); + auto new_series = global_render->createSeries(kind); new_element = new_series; element->parentElement()->insertBefore(new_series, element); - plot_parent->setAttribute("kind", static_cast(element->getAttribute("kind"))); + plot_parent->setAttribute("_kind", kind); new_series->setAttribute("x", element->getAttribute("x")); new_series->setAttribute("y", element->getAttribute("y")); new_series->setAttribute("z", element->getAttribute("z")); @@ -17940,19 +18738,18 @@ void updateFilter(const std::shared_ptr &element, const std::strin new_series->setAttribute("_delete_children", 2); } else if (std::find(barplot_group.begin(), barplot_group.end(), value) != barplot_group.end() && - std::find(barplot_group.begin(), barplot_group.end(), - static_cast(element->getAttribute("kind"))) != barplot_group.end()) + std::find(barplot_group.begin(), barplot_group.end(), kind) != barplot_group.end()) { - auto new_series = global_render->createSeries(static_cast(element->getAttribute("kind"))); + auto new_series = global_render->createSeries(kind); new_element = new_series; element->parentElement()->insertBefore(new_series, element); - plot_parent->setAttribute("kind", static_cast(element->getAttribute("kind"))); + plot_parent->setAttribute("_kind", kind); new_series->setAttribute("x", element->getAttribute("x")); new_series->setAttribute("_bbox_id", -1); if (element->hasAttribute("orientation")) new_series->setAttribute("orientation", static_cast(element->getAttribute("orientation"))); if (static_cast(central_region->getAttribute("keep_window"))) setRanges(element, new_series); - if (static_cast(element->getAttribute("kind")) == "hist") + if (kind == "hist") { new_series->setAttribute("weights", element->getAttribute("y")); } @@ -17976,15 +18773,28 @@ void updateFilter(const std::shared_ptr &element, const std::strin element->remove(); new_series->setAttribute("_update_required", true); new_series->setAttribute("_delete_children", 2); + + if (kind == "barplot" || kind == "hist") + { + int series_count = new_series->parentElement()->querySelectorsAll("series_" + kind).size(); + // if more than 1 barplot/hist series is displayed they could overlap each other -> problem + // to make everything visible again transparency must be used + for (const auto &series : new_series->parentElement()->querySelectorsAll("series_" + kind)) + { + if (series_count > 1 && !series->hasAttribute("transparency")) + { + series->setAttribute("transparency", 0.5); + } + } + } } else if (std::find(hexbin_group.begin(), hexbin_group.end(), value) != hexbin_group.end() && - std::find(hexbin_group.begin(), hexbin_group.end(), - static_cast(element->getAttribute("kind"))) != hexbin_group.end()) + std::find(hexbin_group.begin(), hexbin_group.end(), kind) != hexbin_group.end()) { - auto new_series = global_render->createSeries(static_cast(element->getAttribute("kind"))); + auto new_series = global_render->createSeries(kind); new_element = new_series; element->parentElement()->insertBefore(new_series, element); - plot_parent->setAttribute("kind", static_cast(element->getAttribute("kind"))); + plot_parent->setAttribute("_kind", kind); new_series->setAttribute("x", element->getAttribute("x")); new_series->setAttribute("y", element->getAttribute("y")); new_series->setAttribute("_bbox_id", -1); @@ -17997,11 +18807,30 @@ void updateFilter(const std::shared_ptr &element, const std::strin new_series->setAttribute("_update_required", true); new_series->setAttribute("_delete_children", 2); } + else if (std::find(polar_line_group.begin(), polar_line_group.end(), value) != polar_line_group.end() && + std::find(polar_line_group.begin(), polar_line_group.end(), kind) != polar_line_group.end()) + { + auto new_series = global_render->createSeries(kind); + new_element = new_series; + element->parentElement()->insertBefore(new_series, element); + plot_parent->setAttribute("_kind", kind); + new_series->setAttribute("x", element->getAttribute("x")); + new_series->setAttribute("y", element->getAttribute("y")); + new_series->setAttribute("_bbox_id", -1); + if (element->hasAttribute("clip_negative")) + new_series->setAttribute("clip_negative", element->getAttribute("clip_negative")); + for (const auto &child : element->children()) + { + child->remove(); + } + element->remove(); + new_series->setAttribute("_update_required", true); + new_series->setAttribute("_delete_children", 2); + } else { element->setAttribute("kind", value); - fprintf(stderr, "Update kind %s to %s is not possible\n", - static_cast(element->getAttribute("kind")).c_str(), value.c_str()); + fprintf(stderr, "Update kind %s to %s is not possible\n", kind.c_str(), value.c_str()); std::cerr << toXML(element->getRootNode(), GRM::SerializerOptions{std::string(2, ' ')}) << "\n"; } @@ -18023,9 +18852,9 @@ void updateFilter(const std::shared_ptr &element, const std::strin } /* update coordinate system if needed */ - std::vector colorbar_group = {"quiver", "contour", "contourf", "hexbin", - "polar_heatmap", "heatmap", "surface", "volume", - "trisurface", "tricontour"}; + std::vector colorbar_group = { + "quiver", "contour", "contourf", "hexbin", "polar_heatmap", "nonuniform_polar_heatmap", + "heatmap", "surface", "volume", "trisurface", "tricontour"}; std::shared_ptr coordinate_system = plot->querySelectors("coordinate_system"); std::string new_kind = static_cast(new_element->getAttribute("kind")); @@ -18193,6 +19022,7 @@ void updateFilter(const std::shared_ptr &element, const std::strin child->setAttribute("draw_grid", false); if (axis_type == "y" && orientation == "vertical") child->setAttribute("draw_grid", false); + child->setAttribute("_delete_children", 2); } } else @@ -18211,21 +19041,22 @@ void updateFilter(const std::shared_ptr &element, const std::strin } } } - if (grplot && (new_kind == "barplot" || new_kind == "stem")) + if (grplot && str_equals_any(new_kind, "barplot", "stem")) { if (coordinate_system->hasAttribute("y_line")) coordinate_system->setAttribute("y_line", true); } - else if (grplot && (old_kind == "barplot" || old_kind == "stem")) + else if (grplot && str_equals_any(old_kind, "barplot", "stem")) { if (coordinate_system->hasAttribute("y_line")) coordinate_system->setAttribute("y_line", false); } // heatmap and marginal_heatmap have a different default behaviour when it comes to adjust lims - if (grplot && (new_kind == "heatmap" || new_kind == "marginal_heatmap")) + if (grplot && str_equals_any(new_kind, "heatmap", "marginal_heatmap", "barplot")) { bool no_other_kind = true; for (const auto &series : central_region->children()) { - if (starts_with(series->localName(), "series_") && series->localName() != "series_heatmap") + if (starts_with(series->localName(), "series_") && + (!str_equals_any(series->localName(), "series_barplot", "series_heatmap"))) { no_other_kind = false; break; @@ -18243,7 +19074,7 @@ void updateFilter(const std::shared_ptr &element, const std::strin plot_parent->setAttribute("adjust_z_lim", false); } } - else if (grplot && (old_kind == "heatmap" || old_kind == "marginal_heatmap")) + else if (grplot && str_equals_any(new_kind, "heatmap", "marginal_heatmap", "barplot")) { for (const auto &child : coordinate_system->children()) { @@ -18255,13 +19086,13 @@ void updateFilter(const std::shared_ptr &element, const std::strin } // need to change tick_orientation if old_kind was heatmap, marginal_heatmap or shade and no other // series of these kinds is left - if (grplot && (str_equals_any(old_kind, "heatmap", "marginal_heatmap", "shade"))) + if (grplot && (str_equals_any(old_kind, "contourf", "heatmap", "marginal_heatmap", "shade"))) { bool one_of_these_kinds_left = true; for (const auto &series : central_region->children()) { if (starts_with(series->localName(), "series_") && - !str_equals_any(series->localName(), "series_heatmap", "series_shade")) + !str_equals_any(series->localName(), "series_contourf", "series_heatmap", "series_shade")) { one_of_these_kinds_left = false; break; @@ -18341,9 +19172,10 @@ void updateFilter(const std::shared_ptr &element, const std::strin { element->setAttribute("_update_required", true); element->setAttribute("_delete_children", 1); - if (str_equals_any(attr, "bin_edges", "bin_widths", "bins", "c", "draw_edges", "inner_series", - "levels", "marginal_heatmap_kind", "num_bins", "px", "py", "pz", "stairs", "u", - "v", "x", "x_colormap", "y", "y_colormap", "z")) + if (str_equals_any(attr, "clip_negative")) element->setAttribute("_delete_children", 0); + if (str_equals_any(attr, "bin_edges", "bin_widths", "bins", "c", "draw_edges", "error_bar_style", + "inner_series", "levels", "marginal_heatmap_kind", "num_bins", "px", "py", "pz", + "stairs", "u", "v", "x", "x_colormap", "y", "y_colormap", "z")) element->setAttribute("_delete_children", 2); if (attr == "orientation") { @@ -18368,7 +19200,7 @@ void updateFilter(const std::shared_ptr &element, const std::strin { // conditional critical attributes auto kind = static_cast(element->getAttribute("kind")); - if (kind == "heatmap" || kind == "polar_heatmap") + if (kind == "heatmap" || kind == "polar_heatmap" || kind == "nonuniform_polar_heatmap") { if (element->hasAttribute("c_range_max") && element->hasAttribute("c_range_min")) { @@ -18379,7 +19211,8 @@ void updateFilter(const std::shared_ptr &element, const std::strin } } } - if (kind == "heatmap" || kind == "surface" || kind == "polar_heatmap") + if (kind == "heatmap" || kind == "surface" || kind == "polar_heatmap" || + kind == "nonuniform_polar_heatmap") { if (!element->hasAttribute("x") && !element->hasAttribute("y")) { @@ -18443,8 +19276,9 @@ void updateFilter(const std::shared_ptr &element, const std::strin } // reset the bounding boxes for elements in list - for (const std::string name : {"bar", "pie_segment", "colorbar", "polar_bar", "coordinate_system", - "axes_text_group", "plot", "error_bar", "integral", "integral_group"}) + for (const std::string name : + {"bar", "pie_segment", "colorbar", "polar_bar", "coordinate_system", "plot", "error_bar", "integral", + "integral_group", "tick_group", "rho_axes", "theta_axes"}) { for (const auto &elem : element->querySelectorsAll(name)) { @@ -18469,6 +19303,8 @@ void updateFilter(const std::shared_ptr &element, const std::strin { if (starts_with(child->localName(), "series_")) resetOldBoundingBoxes(child); } + auto rho_axes = element->querySelectors("rho_axes"); + if (rho_axes != nullptr && rho_axes->hasAttribute("_r_max")) rho_axes->removeAttribute("_r_max"); // reset the bounding boxes for elements in list for (const std::string name : {"bar", "pie_segment", "colorbar", "polar_bar", "axes_text_group", @@ -18489,54 +19325,60 @@ void updateFilter(const std::shared_ptr &element, const std::strin std::find(plot_critical_attributes.begin(), plot_critical_attributes.end(), attr) != plot_critical_attributes.end()) { - for (const auto &child : element->children()) + for (const auto &plot_child : element->children()) { - if (starts_with(child->localName(), "series_")) + for (const auto &child : plot_child->children()) { - child->setAttribute("_update_required", true); - - // reset data when log is set to false - if (attr == "x_log") + if (starts_with(child->localName(), "series_")) { - if (child->hasAttribute("x") && child->hasAttribute("_x_org")) + child->setAttribute("_update_required", true); + + // reset data when log is set to false + if (attr == "x_log") { - auto x_org = static_cast(element->getAttribute("_x_org")); - element->setAttribute("x", x_org); + if (child->hasAttribute("x") && child->hasAttribute("_x_org")) + { + auto x_org = static_cast(element->getAttribute("_x_org")); + element->setAttribute("x", x_org); + } + if (element->hasAttribute("x_range_min") && !element->hasAttribute("_x_range_min_org")) + element->setAttribute("x_range_min", + static_cast(element->getAttribute("_x_range_min_org"))); + if (element->hasAttribute("x_range_max") && !element->hasAttribute("_x_range_max_org")) + element->setAttribute("x_range_max", + static_cast(element->getAttribute("_x_range_max_org"))); + element->setAttribute("_update_limits", true); } - if (element->hasAttribute("x_range_min") && !element->hasAttribute("_x_range_min_org")) - element->setAttribute("x_range_min", - static_cast(element->getAttribute("_x_range_min_org"))); - if (element->hasAttribute("x_range_max") && !element->hasAttribute("_x_range_max_org")) - element->setAttribute("x_range_max", - static_cast(element->getAttribute("_x_range_max_org"))); - } - if (attr == "y_log") - { - if (child->hasAttribute("y") && child->hasAttribute("_y_org")) + if (attr == "y_log") { - auto y_org = static_cast(element->getAttribute("_y_org")); - element->setAttribute("y", y_org); + if (child->hasAttribute("y") && child->hasAttribute("_y_org")) + { + auto y_org = static_cast(element->getAttribute("_y_org")); + element->setAttribute("y", y_org); + } + if (element->hasAttribute("y_range_min") && !element->hasAttribute("_y_range_min_org")) + element->setAttribute("y_range_min", + static_cast(element->getAttribute("_y_range_min_org"))); + if (element->hasAttribute("y_range_max") && !element->hasAttribute("_y_range_max_org")) + element->setAttribute("y_range_max", + static_cast(element->getAttribute("_y_range_max_org"))); + element->setAttribute("_update_limits", true); } - if (element->hasAttribute("y_range_min") && !element->hasAttribute("_y_range_min_org")) - element->setAttribute("y_range_min", - static_cast(element->getAttribute("_y_range_min_org"))); - if (element->hasAttribute("y_range_max") && !element->hasAttribute("_y_range_max_org")) - element->setAttribute("y_range_max", - static_cast(element->getAttribute("_y_range_max_org"))); - } - if (attr == "z_log") - { - if (child->hasAttribute("z") && child->hasAttribute("_z_org")) + if (attr == "z_log") { - auto z_org = static_cast(element->getAttribute("_z_org")); - element->setAttribute("z", z_org); + if (child->hasAttribute("z") && child->hasAttribute("_z_org")) + { + auto z_org = static_cast(element->getAttribute("_z_org")); + element->setAttribute("z", z_org); + } + if (element->hasAttribute("z_range_min") && !element->hasAttribute("_z_range_min_org")) + element->setAttribute("z_range_min", + static_cast(element->getAttribute("_z_range_min_org"))); + if (element->hasAttribute("z_range_max") && !element->hasAttribute("_z_range_max_org")) + element->setAttribute("z_range_max", + static_cast(element->getAttribute("_z_range_max_org"))); + element->setAttribute("_update_limits", true); } - if (element->hasAttribute("z_range_min") && !element->hasAttribute("_z_range_min_org")) - element->setAttribute("z_range_min", - static_cast(element->getAttribute("_z_range_min_org"))); - if (element->hasAttribute("z_range_max") && !element->hasAttribute("_z_range_max_org")) - element->setAttribute("z_range_max", - static_cast(element->getAttribute("_z_range_max_org"))); } } } @@ -18548,6 +19390,67 @@ void updateFilter(const std::shared_ptr &element, const std::strin if (element->hasAttribute("y_scale_ndc")) element->removeAttribute("y_scale_ndc"); if (element->hasAttribute("y_shift_ndc")) element->removeAttribute("y_shift_ndc"); resetOldBoundingBoxes(element); + + if (str_equals_any(element->localName(), "side_plot_region", "text_region")) + { + auto new_location = static_cast(element->getAttribute("location")); + auto parent = element->parentElement(); + auto other_parent = + parent->parentElement()->querySelectors("side_region[location=" + new_location + "]"); + auto parent_text = static_cast(parent->getAttribute("text_content")); + auto parent_width = static_cast(parent->getAttribute("width")); + auto parent_offset = static_cast(parent->getAttribute("offset")); + auto other_parent_text = static_cast(other_parent->getAttribute("text_content")); + auto other_parent_width = static_cast(other_parent->getAttribute("width")); + auto other_parent_offset = static_cast(other_parent->getAttribute("offset")); + + for (const auto &child : other_parent->querySelectorsAll(element->localName())) + { + // figure out if an element needs to be swapped back + if (child != element) + { + parent->appendChild(child); + child->setAttribute("_update_required", 1); + child->setAttribute("location", value); + resetOldBoundingBoxes(child); + } + } + // move element between both regions + other_parent->appendChild(element); + if (element->localName() == "text_region") + { + other_parent->setAttribute("text_content", parent_text); + if (!other_parent_text.empty()) + parent->setAttribute("text_content", other_parent_text); + else + parent->removeAttribute("text_content"); + } + + if (element->localName() == "side_plot_region") + { + // reset width and offset cause with the side_plot_region change they could be different + other_parent->setAttribute("offset", parent_offset); + other_parent->setAttribute("width", parent_width); + parent->setAttribute("offset", other_parent_offset); + parent->setAttribute("width", other_parent_width); + } + element->setAttribute("_update_required", 1); + resetOldBoundingBoxes(element); + } + else if (element->localName() == "side_region") + { + // switch the complete side_region if its location gets changed + auto new_location = static_cast(element->getAttribute("location")); + for (const auto &side_region : + element->parentElement()->querySelectorsAll("side_region[location=" + new_location + "]")) + { + if (side_region != element) + { + side_region->setAttribute("location", value); + resetOldBoundingBoxes(side_region); + } + } + } } else if (element->localName() == "integral" && std::find(integral_critical_attributes.begin(), integral_critical_attributes.end(), attr) != @@ -18600,13 +19503,76 @@ void updateFilter(const std::shared_ptr &element, const std::strin { auto val = static_cast(element->getAttribute("value")); auto map_idx = static_cast(element->parentElement()->getAttribute("_axis_id")); - tick_modification_map[map_idx][val].emplace(attr, element->getAttribute(attr)); + if (tick_modification_map[map_idx][val].count(attr) > 0) + { + tick_modification_map[map_idx][val][attr] = element->getAttribute(attr); + } + else + { + tick_modification_map[map_idx][val].emplace(attr, element->getAttribute(attr)); + } } else if (element->localName() == "text" && element->parentElement()->localName() == "tick_group") { auto val = static_cast(element->parentElement()->getAttribute("value")); auto map_idx = static_cast(element->parentElement()->parentElement()->getAttribute("_axis_id")); - tick_modification_map[map_idx][val].emplace(attr, element->getAttribute(attr)); + if (tick_modification_map[map_idx][val].count(attr) > 0) + { + tick_modification_map[map_idx][val][attr] = element->getAttribute(attr); + } + else + { + tick_modification_map[map_idx][val].emplace(attr, element->getAttribute(attr)); + } + } + else if (element->localName() == "tick" && element->parentElement()->localName() == "tick_group") + { + auto val = static_cast(element->getAttribute("value")); + auto map_idx = static_cast(element->parentElement()->parentElement()->getAttribute("_axis_id")); + if (tick_modification_map[map_idx][val].count(attr) > 0) + { + tick_modification_map[map_idx][val][attr] = element->getAttribute(attr); + } + else + { + tick_modification_map[map_idx][val].emplace(attr, element->getAttribute(attr)); + } + } + else if (attr == "tick_size") + { + element->setAttribute("_tick_size_set_by_user", element->getAttribute(attr)); + } + else if (attr == "x_lim_min" || attr == "x_lim_max") + { + auto coordinate_system = element->querySelectors("coordinate_system"); + auto plot_type = static_cast(coordinate_system->getAttribute("plot_type")); + if (plot_type == "polar") + { + for (const auto &child : coordinate_system->children()) + { + if (child->localName() == "theta_axes") + { + child->setAttribute("_update_required", true); + child->setAttribute("_delete_children", 2); + } + } + } + } + else if (element->localName() == "plot" && attr == "polar_with_pan") + { + auto central_region = element->querySelectors("central_region"); + auto coordinate_system = central_region->querySelectors("coordinate_system"); + auto plot_type = static_cast(coordinate_system->getAttribute("plot_type")); + if (plot_type == "polar") + { + global_render->setClipRegion(central_region, !static_cast(element->getAttribute(attr))); + global_render->setSelectSpecificXform(central_region, 1); + processClipRegion(central_region); + element->setAttribute("reset_ranges", 1); + + auto theta_axes = coordinate_system->querySelectors("theta_axes"); + theta_axes->setAttribute("_delete_children", 2); + } } } global_root->setAttribute("_modified", true); @@ -18618,9 +19584,7 @@ void updateFilter(const std::shared_ptr &element, const std::strin void renderCaller() { if (global_root && static_cast(global_root->getAttribute("_modified")) && automatic_update) - { - global_render->process_tree(); - } + global_render->process_tree(); } void GRM::Render::setActiveFigure(const std::shared_ptr &element) diff --git a/lib/grm/src/grm/import.cxx b/lib/grm/src/grm/import.cxx index 7fee0a6f9..62ef21c7a 100644 --- a/lib/grm/src/grm/import.cxx +++ b/lib/grm/src/grm/import.cxx @@ -27,6 +27,7 @@ static std::map key_to_types{ {"bin_edges", "nD"}, {"bin_width", "d"}, {"c", "nD"}, + {"clip_negative", "i"}, {"colormap", "i"}, {"draw_edges", "i"}, {"edge_color", "ddd"}, @@ -34,6 +35,7 @@ static std::map key_to_types{ {"edge_width", "d"}, {"equal_up_and_down_error", "i"}, {"error", "a"}, + {"error_bar_style", "i"}, {"grplot", "i"}, {"ind_bar_color", "nA"}, {"ind_edge_color", "nA"}, @@ -42,6 +44,7 @@ static std::map key_to_types{ {"int_limits_low", "nD"}, {"isovalue", "d"}, {"keep_aspect_ratio", "i"}, + {"keep_radii_axes", "i"}, {"kind", "s"}, {"levels", "i"}, {"line_spec", "s"}, @@ -96,11 +99,12 @@ static std::map key_to_types{ /* ~~~~~~~~~~~~~~~~~~~~~~~~~ kind types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ static std::list kind_types = { - "barplot", "contour", "contourf", "heatmap", "hexbin", "hist", - "imshow", "isosurface", "line", "marginal_heatmap", "polar", "polar_heatmap", - "polar_histogram", "pie", "plot3", "scatter", "scatter3", "shade", - "surface", "stem", "stairs", "tricontour", "trisurface", "quiver", - "volume", "wireframe"}; + "barplot", "contour", "contourf", "heatmap", "hexbin", + "hist", "imshow", "isosurface", "line", "marginal_heatmap", + "polar_line", "polar_heatmap", "polar_histogram", "polar_scatter", "pie", + "plot3", "scatter", "scatter3", "shade", "surface", + "stem", "stairs", "tricontour", "trisurface", "quiver", + "volume", "wireframe"}; /* ~~~~~~~~~~~~~~~~~~~~~~~~~ alias for keys ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ @@ -220,9 +224,9 @@ err_t parse_columns(std::list *columns, const char *colms) } err_t read_data_file(const std::string &path, std::vector>> &data, - std::vector &x_data, std::vector &error_data, std::vector &labels, - grm_args_t *args, const char *colms, const char *x_colms, const char *y_colms, const char *e_colms, - PlotRange *ranges) + std::vector &x_data, std::vector &y_data, std::vector &error_data, + std::vector &labels, grm_args_t *args, const char *colms, const char *x_colms, + const char *y_colms, const char *e_colms, PlotRange *ranges) { std::string line; std::string token; @@ -267,12 +271,13 @@ err_t read_data_file(const std::string &path, std::vector 0)) || - (columns.empty() && col < labels.size() && (!use_bins || col > 0))) + (columns.empty() && (!use_bins || col > 0))) { if ((row == 0 && (col == use_bins || col == columns.front())) || (depth_change && (col == use_bins || col == columns.front())) || @@ -438,6 +445,9 @@ err_t read_data_file(const std::string &path, std::vector>> file_data; - std::vector x_data, error_data; + std::vector x_data, y_data, error_data; std::vector labels; std::vector labels_c; std::vector series; @@ -584,9 +594,9 @@ int grm_interactive_plot_from_file(grm_args_t *args, int argc, char **argv) file_args->file_error_columns.clear(); file_args->file_error_columns = equal_up_and_down_error ? "2" : "2,3"; } - if (read_data_file(file_args->file_path, file_data, x_data, error_data, labels, args, file_args->file_columns.c_str(), - file_args->file_x_columns.c_str(), file_args->file_y_columns.c_str(), - file_args->file_error_columns.c_str(), &ranges)) + if (read_data_file(file_args->file_path, file_data, x_data, y_data, error_data, labels, args, + file_args->file_columns.c_str(), file_args->file_x_columns.c_str(), + file_args->file_y_columns.c_str(), file_args->file_error_columns.c_str(), &ranges)) { return 0; } @@ -648,6 +658,7 @@ int grm_interactive_plot_from_file(grm_args_t *args, int argc, char **argv) if (str_equals_any(kind, "contour", "contourf", "heatmap", "imshow", "marginal_heatmap", "surface", "wireframe")) { int x_dim = cols, y_dim = rows, z_dim = rows * cols; + double xmin, xmax, ymin, ymax; if (cols <= 1 || (xyz_file && cols < 3)) { fprintf(stderr, "Insufficient data for plot type (%s)\n", kind); @@ -676,6 +687,19 @@ int grm_interactive_plot_from_file(grm_args_t *args, int argc, char **argv) std::vector xi(x_dim), yi(y_dim), zi(z_dim); + if (!grm_args_values(args, "x_range", "dd", &xmin, &xmax)) + { + xmin = 0.0; + xmax = x_dim - 1.0; + } + if (!grm_args_values(args, "y_range", "dd", &ymin, &ymax) && !use_bins) + { + ymin = 0.0; + ymax = y_dim - 1.0; + } + adjust_ranges(&ranges.xmin, &ranges.xmax, xmin, xmax); + adjust_ranges(&ranges.ymin, &ranges.ymax, ymin, ymax); + if (use_bins) { try @@ -689,8 +713,6 @@ int grm_interactive_plot_from_file(grm_args_t *args, int argc, char **argv) labels[0].c_str(), labels[cols - 1].c_str()); } } - adjust_ranges(&ranges.xmin, &ranges.xmax, 0.0, (double)x_dim - 1.0); - adjust_ranges(&ranges.ymin, &ranges.ymax, 0.0, (double)y_dim - 1.0); ranges.ymax = (ranges.ymax <= ranges.ymin) ? ranges.ymax + ranges.ymin : ranges.ymax; if (xyz_file) @@ -713,12 +735,12 @@ int grm_interactive_plot_from_file(grm_args_t *args, int argc, char **argv) { for (col = 0; col < cols; ++col) { - xi[col] = ranges.xmin + (ranges.xmax - ranges.xmin) * ((double)col / ((double)cols - 1)); + xi[col] = ranges.xmin + (ranges.xmax - ranges.xmin) * ((double)col / ((double)x_dim - 1)); for (row = 0; row < rows; ++row) { if (col == 0) { - yi[row] = ranges.ymin + (ranges.ymax - ranges.ymin) * ((double)row / ((double)rows - 1)); + yi[row] = ranges.ymin + (ranges.ymax - ranges.ymin) * ((double)row / ((double)y_dim - 1)); } zi[row * cols + col] = file_data[depth][col][row]; } @@ -753,8 +775,16 @@ int grm_interactive_plot_from_file(grm_args_t *args, int argc, char **argv) std::vector filtered_error_columns; int err = 0, col_group_elem = 3, down_err_off = 2; const char *spec; + int series_num; + int y_cnt = 0, x_cnt = 0, err_cnt = 0; + double xmin, xmax; - adjust_ranges(&ranges.xmin, &ranges.xmax, 0.0, (double)rows - 1.0); + if (!grm_args_values(args, "x_range", "dd", &xmin, &xmax)) + { + xmin = 0.0; + xmax = rows - 1.0; + } + adjust_ranges(&ranges.xmin, &ranges.xmax, xmin, xmax); cols += x_data.size() + error_data.size(); // calculate x-data if x_data is empty which means no x given @@ -787,6 +817,8 @@ int grm_interactive_plot_from_file(grm_args_t *args, int argc, char **argv) double min_val = INFINITY, max_val = -INFINITY; for (col = 0; col < cols - err; col++) { + if (std::find(x_data.begin(), x_data.end(), col) != x_data.end()) continue; + if (std::find(error_data.begin(), error_data.end(), col) != error_data.end()) continue; min_val = std::min( min_val, *std::min_element( @@ -896,46 +928,64 @@ int grm_interactive_plot_from_file(grm_args_t *args, int argc, char **argv) } } } - int y_cnt = 0, x_cnt = 0, err_cnt = 0; + if (!x_data.empty() || !error_data.empty()) { - for (col = 0; col < cols - x_data.size() - error_data.size(); col++) + series_num = y_data.size(); + for (col = 0; col < series_num; col++) { series[col] = grm_args_new(); } } + else + { + series_num = cols - err; + } for (col = 0; col < cols - err; col++) { - if (x_data.empty() && error_data.empty()) + if (x_data.empty() && y_data.empty() && error_data.empty()) { series[col] = grm_args_new(); grm_args_push(series[col], "x", "nD", rows, x.data()); grm_args_push(series[col], "y", "nD", rows, file_data[depth][col + ((col < err / down_err_off) ? col * down_err_off : err)].data()); - if (col < err / down_err_off) grm_args_push(series[col], "error", "a", error_vec[col]); - if (!labels.empty()) + if (col < err / down_err_off) { - labels_c.push_back(labels[col].c_str()); + int error_bar_style; + grm_args_push(series[col], "error", "a", error_vec[col]); + if (grm_args_values(args, "error_bar_style", "i", &error_bar_style)) + grm_args_push(series[col], "error_bar_style", "i", error_bar_style); } + if (!labels.empty() && labels.size() > col) labels_c.push_back(labels[col].c_str()); if (grm_args_values(args, "line_spec", "s", &spec)) grm_args_push(series[col], "line_spec", "s", spec); } else { if (std::find(x_data.begin(), x_data.end(), col) != x_data.end()) { + int error_bar_style; grm_args_push(series[x_cnt], "x", "nD", rows, file_data[depth][col].data()); + if (grm_args_values(args, "error_bar_style", "i", &error_bar_style)) + grm_args_push(series[x_cnt], "error_bar_style", "i", error_bar_style); x_cnt += 1; } - else if (std::find(error_data.begin(), error_data.end(), col) == error_data.end()) + else if (std::find(y_data.begin(), y_data.end(), col) != y_data.end()) { grm_args_push(series[y_cnt], "y", "nD", rows, file_data[depth][col].data()); - if (!labels.empty()) labels_c.push_back(labels[col].c_str()); + if (!labels.empty() && labels.size() > y_cnt) labels_c.push_back(labels[y_cnt].c_str()); if (grm_args_values(args, "line_spec", "s", &spec)) grm_args_push(series[y_cnt], "line_spec", "s", spec); y_cnt += 1; } - else if (std::find(filtered_error_columns.begin(), filtered_error_columns.end(), col) == - filtered_error_columns.end()) + else if (!equal_up_and_down_error && error != nullptr && + std::find(filtered_error_columns.begin(), filtered_error_columns.end(), col) == + filtered_error_columns.end()) + { + grm_args_push(series[err_cnt], "error", "a", error_vec[err_cnt]); + err_cnt += 1; + } + else if (equal_up_and_down_error && + std::find(error_data.begin(), error_data.end(), col) != error_data.end()) { grm_args_push(series[err_cnt], "error", "a", error_vec[err_cnt]); err_cnt += 1; @@ -943,11 +993,8 @@ int grm_interactive_plot_from_file(grm_args_t *args, int argc, char **argv) } } cols -= x_data.size() + error_data.size(); - grm_args_push(args, "series", "nA", cols - err, series.data()); - if (!labels_c.empty()) - { - grm_args_push(args, "labels", "nS", cols - err, labels_c.data()); - } + grm_args_push(args, "series", "nA", series_num, series.data()); + if (!labels_c.empty()) grm_args_push(args, "labels", "nS", grm_min(labels_c.size(), series_num), labels_c.data()); } else if (str_equals_any(kind, "isosurface", "volume")) { @@ -973,6 +1020,7 @@ int grm_interactive_plot_from_file(grm_args_t *args, int argc, char **argv) (strcmp(kind, "scatter") == 0 && scatter_with_z)) { double min_x, max_x, min_y, max_y, min_z, max_z; + double xmin, xmax, ymin, ymax, zmin, zmax; if (cols < 3) { fprintf(stderr, "Insufficient data for plot type (%s)\n", kind); @@ -985,20 +1033,35 @@ int grm_interactive_plot_from_file(grm_args_t *args, int argc, char **argv) { min_x = *std::min_element(std::begin(file_data[depth][0]), std::end(file_data[depth][0])); max_x = *std::max_element(std::begin(file_data[depth][0]), std::end(file_data[depth][0])); - adjust_ranges(&ranges.xmin, &ranges.xmax, min_x, max_x); + if (!grm_args_values(args, "x_range", "dd", &xmin, &xmax)) + { + xmin = min_x; + xmax = max_x; + } + adjust_ranges(&ranges.xmin, &ranges.xmax, xmin, xmax); } if (ranges.ymax != INFINITY) { min_y = *std::min_element(std::begin(file_data[depth][1]), std::end(file_data[depth][1])); max_y = *std::max_element(std::begin(file_data[depth][1]), std::end(file_data[depth][1])); - adjust_ranges(&ranges.ymin, &ranges.ymax, min_y, max_y); + if (!grm_args_values(args, "y_range", "dd", &ymin, &ymax)) + { + ymin = min_y; + ymax = max_y; + } + adjust_ranges(&ranges.ymin, &ranges.ymax, ymin, ymax); ranges.ymax = (ranges.ymax <= ranges.ymin) ? ranges.ymax + ranges.ymin : ranges.ymax; } if (ranges.zmax != INFINITY) { min_z = *std::min_element(std::begin(file_data[depth][2]), std::end(file_data[depth][2])); max_z = *std::max_element(std::begin(file_data[depth][2]), std::end(file_data[depth][2])); - adjust_ranges(&ranges.zmin, &ranges.zmax, min_z, max_z); + if (!grm_args_values(args, "z_range", "dd", &zmin, &zmax)) + { + zmin = min_z; + zmax = max_z; + } + adjust_ranges(&ranges.zmin, &ranges.zmax, zmin, zmax); ranges.zmax = (ranges.zmax <= ranges.zmin) ? ranges.zmax + ranges.zmin : ranges.zmax; } for (row = 0; row < rows; ++row) @@ -1022,110 +1085,58 @@ int grm_interactive_plot_from_file(grm_args_t *args, int argc, char **argv) { std::vector x(rows); double xmin, xmax, ymin, ymax; - int y_ind = 0; grm_args_t *error = nullptr; - - if (strcmp(kind, "barplot") == 0) - { - adjust_ranges(&ranges.xmin, &ranges.xmax, 1.0, (double)rows); - } - else - { - adjust_ranges(&ranges.xmin, &ranges.xmax, 0.0, (double)rows - 1.0); - } - if (x_data.empty()) - { - for (row = 0; row < rows; row++) - { - x[row] = ranges.xmin + (ranges.xmax - ranges.xmin) * ((double)row / ((double)rows - 1)); - } - } - else + const char *spec; + std::vector error_vec; + std::vector filtered_error_columns; + int err = 0, col_group_elem = 3, down_err_off = 2; + int series_num = 0; + int err_cnt = 0, y_cnt = 0, x_cnt = 0; + if (!grm_args_values(args, "x_range", "dd", &xmin, &xmax)) { - x = file_data[depth][x_data[0]]; - if (!grm_args_values(args, "x_range", "dd", &xmin, &xmax)) + if (strcmp(kind, "barplot") == 0) { - xmin = *std::min_element(std::begin(file_data[depth][x_data[0]]), std::end(file_data[depth][x_data[0]])); - xmax = *std::max_element(std::begin(file_data[depth][x_data[0]]), std::end(file_data[depth][x_data[0]])); - adjust_ranges(&ranges.xmin, &ranges.xmax, xmin, xmax); - grm_args_push(args, "x_range", "dd", ranges.xmin, ranges.xmax); + xmin = 1; + xmax = rows; } else { - /* apply y_range to the data */ - xmin = *std::min_element(std::begin(file_data[depth][x_data[0]]), std::end(file_data[depth][x_data[0]])); - xmax = *std::max_element(std::begin(file_data[depth][x_data[0]]), std::end(file_data[depth][x_data[0]])); - for (row = 0; row < rows; ++row) - { - x[row] = ranges.xmin + (ranges.xmax - ranges.xmin) / (xmax - xmin) * - ((double)file_data[depth][x_data[0]][row] - xmin); - } + xmin = 0.0; + xmax = rows - 1.0; } } - if (!x_data.empty() || !error_data.empty()) + adjust_ranges(&ranges.xmin, &ranges.xmax, xmin, xmax); + cols += x_data.size() + error_data.size(); + + // precalculate the number of error columns, so they can be removed from the y-data in the following step + if (str_equals_any(kind, "barplot", "hist") && + (grm_args_values(args, "error", "a", &error) || xye_file || equal_up_and_down_error)) { - for (col = 0; col < cols + x_data.size() + error_data.size(); col++) + if (error == nullptr) { - if (std::find(error_data.begin(), error_data.end(), col) == error_data.end() && - std::find(x_data.begin(), x_data.end(), col) == x_data.end()) - { - y_ind = col; - break; - } + error = grm_args_new(); + grm_args_push(args, "error", "a", error); } - } - if (!grm_args_values(args, "y_range", "dd", &ymin, &ymax)) - { - ymin = *std::min_element(std::begin(file_data[depth][y_ind]), std::end(file_data[depth][y_ind])); - ymax = *std::max_element(std::begin(file_data[depth][y_ind]), std::end(file_data[depth][y_ind])); - adjust_ranges(&ranges.ymin, &ranges.ymax, std::min(0.0, ymin), ymax); - grm_args_push(args, "y_range", "dd", ranges.ymin, ranges.ymax); - } - else - { - /* apply y_range to the data */ - ymin = *std::min_element(std::begin(file_data[depth][y_ind]), std::end(file_data[depth][y_ind])); - ymax = *std::max_element(std::begin(file_data[depth][y_ind]), std::end(file_data[depth][y_ind])); - for (row = 0; row < rows; ++row) + + if (equal_up_and_down_error) { - file_data[depth][y_ind][row] = - ranges.ymin + (ranges.ymax - ranges.ymin) / (ymax - 0) * ((double)file_data[depth][y_ind][row] - 0); + col_group_elem -= 1; + down_err_off -= 1; } + err = floor(cols / col_group_elem) * down_err_off; } - if (!grm_args_values(args, "x_range", "dd", &xmin, &xmax)) - { - grm_args_push(args, "x_range", "dd", ranges.xmin, ranges.xmax); - } - - grm_args_push(args, "x", "nD", rows, x.data()); - /* for barplot */ - grm_args_push(args, "y", "nD", rows, file_data[depth][y_ind].data()); - /* for hist */ - grm_args_push(args, "weights", "nD", rows, file_data[depth][y_ind].data()); - /* for stairs */ - grm_args_push(args, "z", "nD", rows, file_data[depth][y_ind].data()); /* the needed calculation to get the errorbars out of the data */ if (grm_args_values(args, "error", "a", &error) || xye_file || equal_up_and_down_error) { int nbins, i; - int col_group_elem = 3, down_err_off = 2; + int color_up, color_down, color; std::vector errors_up(rows); std::vector errors_down(rows); std::vector bins; - if (error == nullptr) - { - error = grm_args_new(); - grm_args_push(args, "error", "a", error); - } - - if (equal_up_and_down_error) - { - col_group_elem -= 1; - down_err_off -= 1; - } - if (cols < col_group_elem || (!error_data.empty() && error_data.size() < down_err_off)) + if ((cols < col_group_elem && error_data.empty()) || + (!error_data.empty() && error_data.size() < down_err_off)) { fprintf(stderr, "Not enough data for error parameter\n"); } @@ -1141,17 +1152,71 @@ int grm_interactive_plot_from_file(grm_args_t *args, int argc, char **argv) if (strcmp(kind, "barplot") == 0) nbins = (int)rows; if (nbins <= rows) { - for (i = 0; i < nbins; i++) + if (error_data.empty()) { - if (error_data.empty()) + err = floor(cols / col_group_elem); + error_vec.resize(err); + for (col = 0; col < err; col++) { - errors_up[i] = file_data[depth][1][i]; - errors_down[i] = file_data[depth][down_err_off][i]; + error_vec[col] = grm_args_new(); + for (i = 0; i < nbins; i++) + { + errors_up[i] = file_data[depth][col + 1 + col * down_err_off][i]; + errors_down[i] = file_data[depth][col + down_err_off + col * down_err_off][i]; + } + grm_args_push(error_vec[col], "relative", "nDD", nbins, errors_up.data(), errors_down.data()); + if (grm_args_values(error, "error_bar_color", "i", &color)) + grm_args_push(error_vec[col], "error_bar_color", "i", color); + if (grm_args_values(error, "downwards_cap_color", "i", &color_down)) + grm_args_push(error_vec[col], "downwards_cap_color", "i", color_down); + if (grm_args_values(error, "upwards_cap_color", "i", &color_up)) + grm_args_push(error_vec[col], "upwards_cap_color", "i", color_up); } - else + err *= down_err_off; + } + else + { + int cnt = 0; + err = 0; + error_vec.resize(equal_up_and_down_error ? error_data.size() : error_data.size() / 2); + for (i = 0; i < error_vec.size(); i++) { - errors_up[i] = file_data[depth][error_data[0]][i]; - errors_down[i] = file_data[depth][equal_up_and_down_error ? error_data[0] : error_data[1]][i]; + error_vec[i] = grm_args_new(); + if (grm_args_values(error, "error_bar_color", "i", &color)) + grm_args_push(error_vec[i], "error_bar_color", "i", color); + if (grm_args_values(error, "downwards_cap_color", "i", &color_down)) + grm_args_push(error_vec[i], "downwards_cap_color", "i", color_down); + if (grm_args_values(error, "upwards_cap_color", "i", &color_up)) + grm_args_push(error_vec[i], "upwards_cap_color", "i", color_up); + } + for (int error_col : error_data) + { + for (i = 0; i < nbins; i++) + { + if (equal_up_and_down_error) + { + errors_up[i] = file_data[depth][error_col][i]; + errors_down[i] = file_data[depth][error_col][i]; + } + else if (cnt % 2 == 0) + { + errors_up[i] = file_data[depth][error_col][i]; + } + else if (cnt % 2 != 0) + { + errors_down[i] = file_data[depth][error_col][i]; + } + } + if (cnt % 2 != 0 || equal_up_and_down_error) + { + grm_args_push(error_vec[floor(cnt / (equal_up_and_down_error ? 1 : 2))], "relative", + "nDD", nbins, errors_up.data(), errors_down.data()); + } + else + { + filtered_error_columns.push_back(error_col); + } + cnt += 1; } } grm_args_push(error, "relative", "nDD", nbins, errors_up.data(), errors_down.data()); @@ -1162,6 +1227,213 @@ int grm_interactive_plot_from_file(grm_args_t *args, int argc, char **argv) } } } + + series_num = (!x_data.empty() || !error_data.empty()) ? y_data.size() : cols - err; + for (col = 0; col < series_num; col++) + { + series[col] = grm_args_new(); + } + + // find min and max value of all x-data and make sure the all data points are inside that range + if (x_data.empty()) + { + for (row = 0; row < rows; row++) + { + x[row] = ranges.xmin + (ranges.xmax - ranges.xmin) * ((double)row / ((double)rows - 1)); + } + for (col = 0; col < series_num; col++) + { + grm_args_push(series[col], "x_range", "dd", ranges.xmin, ranges.xmax); + } + } + else + { + if (!grm_args_values(args, "x_range", "dd", &xmin, &xmax)) + { + double x_min = INFINITY, x_max = -INFINITY; + for (col = 0; col < x_data.size(); col++) + { + xmin = *std::min_element(std::begin(file_data[depth][x_data[col]]), + std::end(file_data[depth][x_data[col]])); + xmax = *std::max_element(std::begin(file_data[depth][x_data[col]]), + std::end(file_data[depth][x_data[col]])); + x_min = grm_min(x_min, xmin); + x_max = grm_max(x_max, xmax); + if (!x_data.empty() && col < series_num) grm_args_push(series[col], "x_range", "dd", xmin, xmax); + } + adjust_ranges(&ranges.xmin, &ranges.xmax, x_min, x_max); + } + else + { + for (col = 0; col < series_num; ++col) + { + grm_args_push(series[col], "x_range", "dd", xmin, xmax); + } + xmin = INFINITY; + xmax = -INFINITY; + for (col = 0; col < x_data.size(); ++col) + { + xmin = grm_min(xmin, *std::min_element(std::begin(file_data[depth][x_data[col]]), + std::end(file_data[depth][x_data[col]]))); + xmax = grm_max(xmax, *std::max_element(std::begin(file_data[depth][x_data[col]]), + std::end(file_data[depth][x_data[col]]))); + } + for (col = 0; col < x_data.size(); ++col) + { + for (row = 0; row < rows; row++) + { + file_data[depth][x_data[col]][row] = + ranges.xmin + (ranges.xmax - ranges.xmin) / (xmax - xmin) * + ((double)file_data[depth][x_data[col]][row] - xmin); + } + } + // special case for barplot and hist cause the x-values and bar_width gets calculated via x_range_min and + // max; without the following code block all series will allways have the same x and same width + if (str_equals_any(kind, "barplot", "hist")) + { + for (col = 0; col < x_data.size(); ++col) + { + xmin = *std::min_element(std::begin(file_data[depth][x_data[col]]), + std::end(file_data[depth][x_data[col]])); + xmax = *std::max_element(std::begin(file_data[depth][x_data[col]]), + std::end(file_data[depth][x_data[col]])); + if (col < series_num) grm_args_push(series[col], "x_range", "dd", xmin, xmax); + } + } + } + } + + // find min and max value of all y-data and make sure the all data points are inside that range + if (!grm_args_values(args, "y_range", "dd", &ymin, &ymax)) + { + double y_min = INFINITY, y_max = -INFINITY; + int tmp_cnt = 0; + for (col = 0; col < cols - err; col++) + { + ymin = grm_min( + 0, *std::min_element( + std::begin(file_data[depth][col + ((col < err / down_err_off) ? col * down_err_off : err)]), + std::end(file_data[depth][col + ((col < err / down_err_off) ? col * down_err_off : err)]))); + ymax = *std::max_element( + std::begin(file_data[depth][col + ((col < err / down_err_off) ? col * down_err_off : err)]), + std::end(file_data[depth][col + ((col < err / down_err_off) ? col * down_err_off : err)])); + y_min = grm_min(y_min, ymin); + y_max = grm_max(y_max, ymax); + if (cols - err == series_num) + grm_args_push(series[col], "y_range", "dd", ymin, ymax); + else if (std::find(y_data.begin(), y_data.end(), col) != y_data.end()) + grm_args_push(series[tmp_cnt++], "y_range", "dd", ymin, ymax); + } + adjust_ranges(&ranges.ymin, &ranges.ymax, std::min(0.0, y_min), y_max); + grm_args_push(args, "y_line_pos", "d", 0.0); + } + else + { + /* apply y_range to the data */ + for (col = 0; col < series_num; ++col) + { + grm_args_push(series[col], "y_range", "dd", ymin, ymax); + } + ymin = INFINITY; + ymax = -INFINITY; + for (col = 0; col < cols; ++col) + { + if (std::find(x_data.begin(), x_data.end(), col) != x_data.end()) continue; + if (std::find(error_data.begin(), error_data.end(), col) != error_data.end()) continue; + ymin = grm_min( + ymin, *std::min_element( + std::begin(file_data[depth][col + ((col < err / down_err_off) ? col * down_err_off : err)]), + std::end(file_data[depth][col + ((col < err / down_err_off) ? col * down_err_off : err)]))); + ymax = grm_max( + ymax, *std::max_element( + std::begin(file_data[depth][col + ((col < err / down_err_off) ? col * down_err_off : err)]), + std::end(file_data[depth][col + ((col < err / down_err_off) ? col * down_err_off : err)]))); + } + if (str_equals_any(kind, "barplot", "hist", "stem")) ymin = grm_min(ymin, 0); + for (col = 0; col < cols; ++col) + { + if (std::find(x_data.begin(), x_data.end(), col) != x_data.end()) continue; + if (std::find(error_data.begin(), error_data.end(), col) != error_data.end()) continue; + for (row = 0; row < rows; ++row) + { + file_data[depth][col][row] = ranges.ymin + (ranges.ymax - ranges.ymin) / (ymax - ymin) * + ((double)file_data[depth][col][row] - ymin); + } + } + grm_args_push(args, "y_line_pos", "d", + ranges.ymin + (ranges.ymax - ranges.ymin) / (ymax - ymin) * (0.0 - ymin)); + } + + // push the data into the container structure + for (col = 0; col < cols - err; col++) + { + if (x_data.empty() && y_data.empty() && error_data.empty()) + { + if (!labels.empty() && labels.size() > col) labels_c.push_back(labels[col].c_str()); + grm_args_push(series[col], "x", "nD", rows, x.data()); + /* for barplot */ + grm_args_push(series[col], "y", "nD", rows, + file_data[depth][col + ((col < err / down_err_off) ? col * down_err_off : err)].data()); + /* for hist */ + grm_args_push(series[col], "weights", "nD", rows, + file_data[depth][col + ((col < err / down_err_off) ? col * down_err_off : err)].data()); + /* for stairs */ + grm_args_push(series[col], "z", "nD", rows, + file_data[depth][col + ((col < err / down_err_off) ? col * down_err_off : err)].data()); + if (grm_args_values(args, "line_spec", "s", &spec)) grm_args_push(series[col], "line_spec", "s", spec); + if (str_equals_any(kind, "barplot", "hist") && series_num > 1) + grm_args_push(series[col], "transparency", "d", 0.5); + if (col < err / down_err_off) + { + int error_bar_style; + grm_args_push(series[col], "error", "a", error_vec[col]); + if (grm_args_values(args, "error_bar_style", "i", &error_bar_style)) + grm_args_push(series[err_cnt], "error_bar_style", "i", error_bar_style); + } + } + else + { + if (std::find(x_data.begin(), x_data.end(), col) != x_data.end()) + { + int error_bar_style; + if (grm_args_values(args, "error_bar_style", "i", &error_bar_style)) + grm_args_push(series[x_cnt], "error_bar_style", "i", error_bar_style); + grm_args_push(series[x_cnt], "x", "nD", rows, file_data[depth][col].data()); + x_cnt += 1; + } + else if (std::find(y_data.begin(), y_data.end(), col) != y_data.end()) + { + if (!labels.empty() && labels.size() > y_cnt) labels_c.push_back(labels[y_cnt].c_str()); + grm_args_push(series[y_cnt], "y", "nD", rows, file_data[depth][col].data()); + /* for hist */ + grm_args_push(series[y_cnt], "weights", "nD", rows, file_data[depth][col].data()); + /* for stairs */ + grm_args_push(series[y_cnt], "z", "nD", rows, file_data[depth][col].data()); + if (grm_args_values(args, "line_spec", "s", &spec)) + grm_args_push(series[y_cnt], "line_spec", "s", spec); + if (str_equals_any(kind, "barplot", "hist") && series_num > 1) + grm_args_push(series[y_cnt], "transparency", "d", 0.5); + y_cnt += 1; + } + else if (!equal_up_and_down_error && str_equals_any(kind, "barplot", "hist") && error != nullptr && + std::find(filtered_error_columns.begin(), filtered_error_columns.end(), col) == + filtered_error_columns.end()) + { + grm_args_push(series[err_cnt], "error", "a", error_vec[err_cnt]); + err_cnt += 1; + } + else if (equal_up_and_down_error && + std::find(error_data.begin(), error_data.end(), col) != error_data.end()) + { + grm_args_push(series[err_cnt], "error", "a", error_vec[err_cnt]); + err_cnt += 1; + } + } + } + cols -= x_data.size() + error_data.size(); + grm_args_push(args, "series", "nA", series_num, series.data()); + + if (!labels_c.empty()) grm_args_push(args, "labels", "nS", grm_min(labels_c.size(), series_num), labels_c.data()); } else if (strcmp(kind, "pie") == 0) { @@ -1202,23 +1474,50 @@ int grm_interactive_plot_from_file(grm_args_t *args, int argc, char **argv) if (cols > 1) fprintf(stderr, "Only the first column gets displayed\n"); grm_args_push(args, "x", "nD", rows, file_data[depth][0].data()); } - else if (strcmp(kind, "polar") == 0) + else if (strcmp(kind, "polar_line") == 0 || strcmp(kind, "polar_scatter") == 0) { - if (cols > 1) fprintf(stderr, "Only the first 2 columns get displayed\n"); - grm_args_push(args, "x", "nD", rows, file_data[depth][0].data()); - grm_args_push(args, "y", "nD", rows, file_data[depth][1].data()); + if (cols % 2 == 1) + { + fprintf(stderr, "For polar_line and polar_scatter plots x and y must allways be given, but in this case the " + "number of columns is odd -> 1 column is missing.\n"); + cols -= 1; + } + for (col = 0; col < cols; col++) + { + if (!labels.empty() && col < labels.size()) labels_c.push_back(labels[col].c_str()); + } + if (!labels_c.empty()) grm_args_push(args, "labels", "nS", grm_min(labels_c.size(), cols), labels_c.data()); + + for (col = 0; col <= cols / 2; col += 2) + { + series[col / 2] = grm_args_new(); + grm_args_push(series[col / 2], "x", "nD", rows, file_data[depth][col].data()); + grm_args_push(series[col / 2], "y", "nD", rows, file_data[depth][col + 1].data()); + } + grm_args_push(args, "series", "nA", cols / 2, series.data()); } else if (strcmp(kind, "polar_heatmap") == 0) { std::vector xi(cols), yi(rows), zi(rows * cols); + double xmin, xmax, ymin, ymax; if (cols <= 1) { fprintf(stderr, "Insufficient data for plot type (%s)\n", kind); return 0; } - adjust_ranges(&ranges.xmin, &ranges.xmax, 0.0, 360.0); - adjust_ranges(&ranges.ymin, &ranges.ymax, 0.0, 3.0); + if (!grm_args_values(args, "x_range", "dd", &xmin, &xmax)) + { + xmin = 0.0; + xmax = 360.0; + } + if (!grm_args_values(args, "y_range", "dd", &ymin, &ymax)) + { + ymin = 0.0; + ymax = 3.0; + } + adjust_ranges(&ranges.xmin, &ranges.xmax, xmin, xmax); + adjust_ranges(&ranges.ymin, &ranges.ymax, ymin, ymax); ranges.ymax = (ranges.ymax <= ranges.ymin) ? ranges.ymax + ranges.ymin : ranges.ymax; for (col = 0; col < cols; ++col) @@ -1243,6 +1542,7 @@ int grm_interactive_plot_from_file(grm_args_t *args, int argc, char **argv) std::vector y(rows); std::vector u(cols * rows); std::vector v(cols * rows); + double xmin, xmax, ymin, ymax; if (depth < 2) { @@ -1250,8 +1550,18 @@ int grm_interactive_plot_from_file(grm_args_t *args, int argc, char **argv) return 0; } - adjust_ranges(&ranges.xmin, &ranges.xmax, 0.0, (double)cols - 1.0); - adjust_ranges(&ranges.ymin, &ranges.ymax, 0.0, (double)rows - 1.0); + if (!grm_args_values(args, "x_range", "dd", &xmin, &xmax)) + { + xmin = 0.0; + xmax = cols - 1.0; + } + if (!grm_args_values(args, "y_range", "dd", &ymin, &ymax)) + { + ymin = 0.0; + ymax = rows - 1.0; + } + adjust_ranges(&ranges.xmin, &ranges.xmax, xmin, xmax); + adjust_ranges(&ranges.ymin, &ranges.ymax, ymin, ymax); ranges.ymax = (ranges.ymax <= ranges.ymin) ? ranges.ymax + ranges.ymin : ranges.ymax; for (col = 0; col < cols; ++col) @@ -1274,10 +1584,21 @@ int grm_interactive_plot_from_file(grm_args_t *args, int argc, char **argv) else if (str_equals_any(kind, "hexbin", "shade")) { double min_x, min_y, max_x, max_y; + double xmin, xmax, ymin, ymax; if (cols > 2) fprintf(stderr, "Only the first 2 columns get displayed\n"); - adjust_ranges(&ranges.xmin, &ranges.xmax, 0.0, (double)cols - 1.0); - adjust_ranges(&ranges.ymin, &ranges.ymax, 0.0, (double)rows - 1.0); + if (!grm_args_values(args, "x_range", "dd", &xmin, &xmax)) + { + xmin = 0.0; + xmax = cols - 1.0; + } + if (!grm_args_values(args, "y_range", "dd", &ymin, &ymax)) + { + ymin = 0.0; + ymax = rows - 1.0; + } + adjust_ranges(&ranges.xmin, &ranges.xmax, xmin, xmax); + adjust_ranges(&ranges.ymin, &ranges.ymax, ymin, ymax); ranges.ymax = (ranges.ymax <= ranges.ymin) ? ranges.ymax + ranges.ymin : ranges.ymax; min_x = *std::min_element(std::begin(file_data[depth][0]), std::end(file_data[depth][0])); max_x = *std::max_element(std::begin(file_data[depth][0]), std::end(file_data[depth][0])); @@ -1307,7 +1628,88 @@ int grm_interactive_plot_from_file(grm_args_t *args, int argc, char **argv) return 1; } -/* ~~~~~~~~~~~~~~~~~~~~~~~~~ input stream parser ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +int grm_context_data_from_file(const std::shared_ptr &context, const std::string &path, + bool interpret_matrix_as_one_column) +{ + size_t cols, rows, depth; + std::vector>> file_data; + std::vector x_data, y_data, error_data; + std::vector labels; + PlotRange ranges = {INFINITY, INFINITY, INFINITY, INFINITY, INFINITY, INFINITY}; + std::shared_ptr root = grm_get_document_root(); + + if (read_data_file(path, file_data, x_data, y_data, error_data, labels, nullptr, "", "", "", "", &ranges)) + { + return 0; + } + + if (!file_data.empty()) + { + depth = file_data.size(); + cols = file_data[0].size(); + rows = file_data[0][0].size(); + depth = (depth == 1) ? 0 : depth; + } + else + { + fprintf(stderr, "File is empty\n"); + return 0; + } + if (cols != labels.size()) + { + fprintf(stderr, + "The number of columns (%zu) doesn't fit the number of context names (%zu). Dummy names will be used " + "instead\n", + cols, labels.size()); + } + + if (!interpret_matrix_as_one_column) + { + for (int col = 0; col < cols; col++) + { + std::string name; + if (!labels.empty() && !labels[col].empty()) + { + name = labels[col]; + } + else + { + auto id = static_cast(root->getAttribute("_id")); + root->setAttribute("_id", ++id); + name = "tmp" + std::to_string(id); + } + (*context)[name] = file_data[depth][col]; + } + } + else + { + std::string name; + std::vector z(rows * cols); + for (int col = 0; col < cols; ++col) + { + for (int row = 0; row < rows; ++row) + { + z[row * cols + col] = file_data[depth][col][row]; + } + } + + if (!labels.empty() && !labels[0].empty()) + { + name = labels[0]; + } + else + { + auto id = static_cast(root->getAttribute("_id")); + root->setAttribute("_id", ++id); + name = "tmp" + std::to_string(id); + } + (*context)[name] = z; + } + return 1; +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~ input stream parser ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ int convert_inputstream_into_args(grm_args_t *args, grm_file_args_t *file_args, int argc, char **argv, PlotRange *ranges) diff --git a/lib/grm/src/grm/import_int.hxx b/lib/grm/src/grm/import_int.hxx index b80d051db..fd8ea0eb1 100644 --- a/lib/grm/src/grm/import_int.hxx +++ b/lib/grm/src/grm/import_int.hxx @@ -42,9 +42,9 @@ struct _grm_file_args_t std::string normalize_line(const std::string &str); err_t parse_columns(std::list *columns, const char *colms); err_t read_data_file(const std::string &path, std::vector>> &data, - std::vector &x_data, std::vector &error_data, std::vector &labels, - grm_args_t *args, const char *colms, const char *x_colms, const char *y_colms, const char *e_colms, - PlotRange *ranges); + std::vector &x_data, std::vector &y_data, std::vector &error_data, + std::vector &labels, grm_args_t *args, const char *colms, const char *x_colms, + const char *y_colms, const char *e_colms, PlotRange *ranges); int convert_inputstream_into_args(grm_args_t *args, grm_file_args_t *file_args, int argc, char **argv, PlotRange *ranges); grm_file_args_t *grm_file_args_new(); diff --git a/lib/grm/src/grm/interaction.cxx b/lib/grm/src/grm/interaction.cxx index 503b0d626..e57c64cd3 100644 --- a/lib/grm/src/grm/interaction.cxx +++ b/lib/grm/src/grm/interaction.cxx @@ -514,7 +514,8 @@ int grm_input(const grm_args_t *input_args) { auto coordinate_system = subplot_element->querySelectors("coordinate_system"); if (coordinate_system->hasAttribute("plot_type") && - static_cast(coordinate_system->getAttribute("plot_type")) == "2d") + (static_cast(coordinate_system->getAttribute("plot_type")) == "2d" || + static_cast(coordinate_system->getAttribute("plot_type")) == "polar")) { logger((stderr, "Reset single subplot coordinate ranges\n")); subplot_element->setAttribute("reset_ranges", 1); @@ -545,12 +546,13 @@ int grm_input(const grm_args_t *input_args) std::string kind; double viewport[4]; auto central_region = subplot_element->querySelectors("central_region"); + auto coordinate_system = subplot_element->querySelectors("coordinate_system"); viewport[0] = static_cast(central_region->getAttribute("viewport_x_min")); viewport[1] = static_cast(central_region->getAttribute("viewport_x_max")); viewport[2] = static_cast(central_region->getAttribute("viewport_y_min")); viewport[3] = static_cast(central_region->getAttribute("viewport_y_max")); - kind = static_cast(subplot_element->getAttribute("kind")); + kind = static_cast(subplot_element->getAttribute("_kind")); if (kind == "marginal_heatmap") { auto current_series = subplot_element->querySelectorsAll("series_heatmap")[0]; @@ -715,8 +717,8 @@ int grm_input(const grm_args_t *input_args) { for (auto &child : side_region->children()) { - std::string childKind = static_cast(child->getAttribute("kind")); - if (childKind == "hist") + std::string child_kind = static_cast(child->getAttribute("kind")); + if (child_kind == "hist") { // reset bar colors // bar level @@ -771,6 +773,10 @@ int grm_input(const grm_args_t *input_args) viewport_mid_y = (viewport[2] + viewport[3]) / 2.0; focus_x = ndc_x - viewport_mid_x; focus_y = ndc_y - viewport_mid_y; + if (static_cast(coordinate_system->getAttribute("plot_type")) == "polar" && + !(subplot_element->hasAttribute("polar_with_pan") && + static_cast(subplot_element->getAttribute("polar_with_pan")))) + focus_x = focus_y = 0.0; logger( (stderr, "Zoom to ndc focus point (%lf, %lf), angle_delta %lf\n", focus_x, focus_y, angle_delta)); double zoom = 1.0 - INPUT_ANGLE_DELTA_FACTOR * angle_delta; @@ -798,6 +804,10 @@ int grm_input(const grm_args_t *input_args) viewport_mid_y = (viewport[2] + viewport[3]) / 2.0; focus_x = ndc_x - viewport_mid_x; focus_y = ndc_y - viewport_mid_y; + if (static_cast(coordinate_system->getAttribute("plot_type")) == "polar" && + !(subplot_element->hasAttribute("polar_with_pan") && + static_cast(subplot_element->getAttribute("polar_with_pan")))) + focus_x = focus_y = 0.0; logger((stderr, "Zoom to ndc focus point (%lf, %lf), factor %lf\n", focus_x, focus_y, factor)); auto panzoom_element = grm_get_render()->createPanzoom(focus_x, focus_y, factor, factor); subplot_element->append(panzoom_element); @@ -840,7 +850,10 @@ int grm_input(const grm_args_t *input_args) } else if (grm_args_values(input_args, "x_shift", "i", &xshift) && grm_args_values(input_args, "y_shift", "i", &yshift) && - !grm_args_values(input_args, "movable_state", "i", &movable_status)) + !grm_args_values(input_args, "movable_state", "i", &movable_status) && + (static_cast(coordinate_system->getAttribute("plot_type")) != "polar" || + (subplot_element->hasAttribute("polar_with_pan") && + static_cast(subplot_element->getAttribute("polar_with_pan"))))) { double ndc_xshift, ndc_yshift, rotation, tilt; int shift_pressed; @@ -994,7 +1007,7 @@ int grm_is3d(const int x, const int y) auto subplot_element = get_subplot_from_ndc_points_using_dom(1, &ndc_x, &ndc_y); - if (subplot_element && str_equals_any(static_cast(subplot_element->getAttribute("kind")), "wireframe", + if (subplot_element && str_equals_any(static_cast(subplot_element->getAttribute("_kind")), "wireframe", "surface", "plot3", "scatter3", "trisurface", "volume", "isosurface")) { return 1; @@ -1258,7 +1271,7 @@ err_t get_tooltips(int mouse_x, int mouse_y, err_t (*tooltip_callback)(int, int, if (subplot_element != nullptr) { - kind = static_cast(subplot_element->getAttribute("kind")); + kind = static_cast(subplot_element->getAttribute("_kind")); if (subplot_element->hasAttribute("orientation")) { orientation = static_cast(subplot_element->getAttribute("orientation")); diff --git a/lib/grm/src/grm/layout.cxx b/lib/grm/src/grm/layout.cxx index 057ca1eab..6b859a8c9 100644 --- a/lib/grm/src/grm/layout.cxx +++ b/lib/grm/src/grm/layout.cxx @@ -10,7 +10,7 @@ using namespace grm; double epsilon = std::numeric_limits::epsilon(); Slice::Slice(int rowStart, int rowStop, int colStart, int colStop) - : rowStart(rowStart), rowStop(rowStop), colStart(colStart), colStop(colStop) + : row_start(rowStart), row_stop(rowStop), col_start(colStart), col_stop(colStop) { if (!this->isPositive()) { @@ -24,13 +24,13 @@ Slice::Slice(int rowStart, int rowStop, int colStart, int colStop) Slice *Slice::copy() { - Slice *copy = new Slice(this->rowStart, this->rowStop, this->colStart, this->colStop); + Slice *copy = new Slice(this->row_start, this->row_stop, this->col_start, this->col_stop); return copy; } bool Slice::isPositive() { - if (rowStart < 0 || rowStop < 0 || colStart < 0 || colStop < 0) + if (row_start < 0 || row_stop < 0 || col_start < 0 || col_stop < 0) { return false; } @@ -42,7 +42,7 @@ bool Slice::isPositive() bool Slice::isForward() { - if (rowStart > rowStop || colStart > colStop) + if (row_start > row_stop || col_start > col_stop) { return false; } @@ -54,14 +54,14 @@ bool Slice::isForward() GridElement::GridElement() { - subplot = new double[4]; + plot = new double[4]; }; GridElement::GridElement(double absHeight, double absWidth, int absHeightPxl, int absWidthPxl, int fitParentsHeight, int fitParentsWidth, double relativeHeight, double relativeWidth, double aspectRatio) - : absHeight(absHeight), absWidth(absWidth), absHeightPxl(absHeightPxl), absWidthPxl(absWidthPxl), - fitParentsHeight(fitParentsHeight), fitParentsWidth(fitParentsWidth), relativeHeight(relativeHeight), - relativeWidth(relativeWidth), aspectRatio(aspectRatio) + : abs_height(absHeight), abs_width(absWidth), abs_height_pxl(absHeightPxl), abs_width_pxl(absWidthPxl), + fit_parents_height(fitParentsHeight), fit_parents_width(fitParentsWidth), relative_height(relativeHeight), + relative_width(relativeWidth), aspect_ratio(aspectRatio) { setAbsHeight(absHeight); setAbsWidth(absWidth); @@ -69,39 +69,39 @@ GridElement::GridElement(double absHeight, double absWidth, int absHeightPxl, in setAbsWidthPxl(absWidthPxl); setRelativeHeight(relativeHeight); setRelativeWidth(relativeWidth); - subplot = new double[4]; + plot = new double[4]; } GridElement::~GridElement() {} -void GridElement::setSubplot(double x1, double x2, double y1, double y2) +void GridElement::setPlot(double x1, double x2, double y1, double y2) { - if (finalized || subplotSet == 0) + if (finalized || plot_set == 0) { - subplot[0] = x1; - subplot[1] = x2; - subplot[2] = y1; - subplot[3] = y2; + plot[0] = x1; + plot[1] = x2; + plot[2] = y1; + plot[3] = y2; finalized = 0; - subplotSet = 1; + plot_set = 1; } else { - if (y1 < subplot[2]) + if (y1 < plot[2]) { - subplot[2] = y1; + plot[2] = y1; } - if (x2 > subplot[1]) + if (x2 > plot[1]) { - subplot[1] = x2; + plot[1] = x2; } } } void GridElement::setAbsHeight(double height) { - if (heightSet && height != -1) + if (height_set && height != -1) { throw ContradictingAttributes("Can only set one height attribute"); } @@ -109,17 +109,17 @@ void GridElement::setAbsHeight(double height) { throw std::invalid_argument("Height has to be between 0 and 1 or be -1"); } - if (arSet && widthSet && height != -1) + if (ar_set && width_set && height != -1) { throw ContradictingAttributes("You cant restrict the height on a plot with fixed width and aspect ratio"); } - absHeight = height; - heightSet = (height != -1) ? 1 : 0; + abs_height = height; + height_set = (height != -1) ? 1 : 0; } void GridElement::setAbsHeightPxl(int height) { - if (heightSet && height != -1) + if (height_set && height != -1) { throw ContradictingAttributes("Can only set one height attribute"); } @@ -127,17 +127,17 @@ void GridElement::setAbsHeightPxl(int height) { throw InvalidArgumentRange("Pixel height has to be an positive integer or be -1"); } - if (arSet && widthSet && height != -1) + if (ar_set && width_set && height != -1) { throw ContradictingAttributes("You cant restrict the height on a plot with fixed width and aspect ratio"); } - absHeightPxl = height; - heightSet = (height != -1) ? 1 : 0; + abs_height_pxl = height; + height_set = (height != -1) ? 1 : 0; } void GridElement::setRelativeHeight(double height) { - if (heightSet && height != -1) + if (height_set && height != -1) { throw ContradictingAttributes("Can only set one height attribute"); } @@ -145,17 +145,17 @@ void GridElement::setRelativeHeight(double height) { throw InvalidArgumentRange("Height has to be between 0 and 1 or be -1"); } - if (arSet && widthSet && height != -1) + if (ar_set && width_set && height != -1) { throw ContradictingAttributes("You cant restrict the height on a plot with fixed width and aspect ratio"); } - relativeHeight = height; - heightSet = (height != -1) ? 1 : 0; + relative_height = height; + height_set = (height != -1) ? 1 : 0; } void GridElement::setAbsWidth(double width) { - if (widthSet && width != -1) + if (width_set && width != -1) { throw ContradictingAttributes("Can only set one width attribute"); } @@ -163,17 +163,17 @@ void GridElement::setAbsWidth(double width) { throw InvalidArgumentRange("Width has to be between 0 and 1 or be -1"); } - if (arSet and heightSet) + if (ar_set and height_set) { throw ContradictingAttributes("You cant restrict the width on a plot with fixed height and aspect ratio"); } - absWidth = width; - widthSet = (width != -1) ? 1 : 0; + abs_width = width; + width_set = (width != -1) ? 1 : 0; } void GridElement::setAbsWidthPxl(int width) { - if (widthSet && width != -1) + if (width_set && width != -1) { throw ContradictingAttributes("Can only set one width attribute"); } @@ -181,17 +181,17 @@ void GridElement::setAbsWidthPxl(int width) { throw InvalidArgumentRange("Pixel Width has to be an positive integer or be -1"); } - if (arSet && heightSet && width != -1) + if (ar_set && height_set && width != -1) { throw ContradictingAttributes("You cant restrict the width on a plot with fixed height and aspect ratio"); } - absWidthPxl = width; - widthSet = (width != -1) ? 1 : 0; + abs_width_pxl = width; + width_set = (width != -1) ? 1 : 0; } void GridElement::setRelativeWidth(double width) { - if (widthSet && width != -1) + if (width_set && width != -1) { throw ContradictingAttributes("Can only set one width attribute"); } @@ -199,12 +199,12 @@ void GridElement::setRelativeWidth(double width) { throw InvalidArgumentRange("Width has to be between 0 and 1 or be -1"); } - if (arSet && heightSet && width != -1) + if (ar_set && height_set && width != -1) { throw ContradictingAttributes("You cant restrict the width on a plot with fixed height and aspect ratio"); } - relativeWidth = width; - widthSet = (width != -1) ? 1 : 0; + relative_width = width; + width_set = (width != -1) ? 1 : 0; } void GridElement::setAspectRatio(double ar) @@ -213,116 +213,116 @@ void GridElement::setAspectRatio(double ar) { throw InvalidArgumentRange("Aspect ration has to be bigger than 0 or be -1"); } - if (widthSet && heightSet && ar != -1) + if (width_set && height_set && ar != -1) { throw ContradictingAttributes("You cant restrict the aspect ratio on a plot with fixed sides"); } - aspectRatio = ar; - arSet = (ar != -1) ? 1 : 0; + aspect_ratio = ar; + ar_set = (ar != -1) ? 1 : 0; } -void GridElement::finalizeSubplot() +void GridElement::finalizePlot() { if (finalized) { return; } - if (absHeight != -1) + if (abs_height != -1) { - double availableHeight = subplot[3] - subplot[2]; - if (absHeight > availableHeight + epsilon) + double availableHeight = plot[3] - plot[2]; + if (abs_height > availableHeight + epsilon) { throw ContradictingAttributes("Absolute height is bigger than available height"); } - double middle = subplot[2] + availableHeight / 2; - subplot[2] = middle - absHeight / 2; - subplot[3] = middle + absHeight / 2; + double middle = plot[2] + availableHeight / 2; + plot[2] = middle - abs_height / 2; + plot[3] = middle + abs_height / 2; } - if (absWidth != -1) + if (abs_width != -1) { - double availableWidth = subplot[1] - subplot[0]; - if (absWidth > availableWidth + epsilon) + double availableWidth = plot[1] - plot[0]; + if (abs_width > availableWidth + epsilon) { throw ContradictingAttributes("Absolute width is bigger than available width"); } - double middle = subplot[0] + availableWidth / 2; - subplot[0] = middle - absWidth / 2; - subplot[1] = middle + absWidth / 2; + double middle = plot[0] + availableWidth / 2; + plot[0] = middle - abs_width / 2; + plot[1] = middle + abs_width / 2; } - if (relativeHeight != -1) + if (relative_height != -1) { - double availableHeight = subplot[3] - subplot[2]; - double middle = subplot[2] + availableHeight / 2; - double newHeight = availableHeight * relativeHeight; - subplot[2] = middle - newHeight / 2; - subplot[3] = middle + newHeight / 2; + double availableHeight = plot[3] - plot[2]; + double middle = plot[2] + availableHeight / 2; + double newHeight = availableHeight * relative_height; + plot[2] = middle - newHeight / 2; + plot[3] = middle + newHeight / 2; } - if (relativeWidth != -1) + if (relative_width != -1) { - double availableWidth = subplot[1] - subplot[0]; - double middle = subplot[0] + availableWidth / 2; - double newWidth = availableWidth * relativeWidth; - subplot[0] = middle - newWidth / 2; - subplot[1] = middle + newWidth / 2; + double availableWidth = plot[1] - plot[0]; + double middle = plot[0] + availableWidth / 2; + double newWidth = availableWidth * relative_width; + plot[0] = middle - newWidth / 2; + plot[1] = middle + newWidth / 2; } /* TODO: implement for pxl */ - if (arSet) + if (ar_set) { - double currentHeigth = (subplot[3] - subplot[2]); - double currentWidth = (subplot[1] - subplot[0]); + double currentHeigth = (plot[3] - plot[2]); + double currentWidth = (plot[1] - plot[0]); double currentAR = currentWidth / currentHeigth; - if (currentAR < aspectRatio) + if (currentAR < aspect_ratio) { - double newHeight = currentWidth / aspectRatio; - double middle = subplot[2] + currentHeigth / 2; - subplot[2] = middle - newHeight / 2; - subplot[3] = middle + newHeight / 2; + double newHeight = currentWidth / aspect_ratio; + double middle = plot[2] + currentHeigth / 2; + plot[2] = middle - newHeight / 2; + plot[3] = middle + newHeight / 2; } else { - double newWidth = currentHeigth * aspectRatio; - double middle = subplot[0] + currentWidth / 2; - subplot[0] = middle - newWidth; - subplot[1] = middle + newWidth; + double newWidth = currentHeigth * aspect_ratio; + double middle = plot[0] + currentWidth / 2; + plot[0] = middle - newWidth; + plot[1] = middle + newWidth; } } - if (subplot_args != nullptr) + if (plot_args != nullptr) { - grm_args_push(subplot_args, "subplot", "nD", 4, subplot); + grm_args_push(plot_args, "subplot", "nD", 4, plot); } - if (elementInDOM != nullptr) + if (element_in_dom != nullptr) { - elementInDOM->setAttribute("plot_x_min", subplot[0]); - elementInDOM->setAttribute("plot_x_max", subplot[1]); - elementInDOM->setAttribute("plot_y_min", subplot[2]); - elementInDOM->setAttribute("plot_y_max", subplot[3]); + element_in_dom->setAttribute("plot_x_min", plot[0]); + element_in_dom->setAttribute("plot_x_max", plot[1]); + element_in_dom->setAttribute("plot_y_min", plot[2]); + element_in_dom->setAttribute("plot_y_max", plot[3]); } finalized = 1; } -double *GridElement::getSubplot() +double *GridElement::getPlot() { - return subplot; + return plot; } void GridElement::setFitParentsHeight(bool fitParentsHeight) { - this->fitParentsHeight = fitParentsHeight; + this->fit_parents_height = fitParentsHeight; } void GridElement::setFitParentsWidth(bool fitParentsWidth) { - this->fitParentsWidth = fitParentsWidth; + this->fit_parents_width = fitParentsWidth; } bool GridElement::isGrid() @@ -379,10 +379,10 @@ void Grid::setElement(int row, int col, GridElement *element) setElement(&newSlice, element); } -void Grid::setElement(int row, int col, grm_args_t *subplot_args) +void Grid::setElement(int row, int col, grm_args_t *plot_args) { Slice newSlice(row, row + 1, col, col + 1); - setElement(&newSlice, subplot_args); + setElement(&newSlice, plot_args); } void Grid::setElement(Slice *slice, GridElement *element) @@ -391,8 +391,8 @@ void Grid::setElement(Slice *slice, GridElement *element) Slice *oldSlice; std::vector oldElements; - nrowsToAllocate = slice->rowStop; - ncolsToAllocate = slice->colStop; + nrowsToAllocate = slice->row_stop; + ncolsToAllocate = slice->col_stop; /* Resize the container if necessary */ upsize(nrowsToAllocate, ncolsToAllocate); @@ -401,9 +401,9 @@ void Grid::setElement(Slice *slice, GridElement *element) try { oldSlice = elementToPosition.at(element); - for (int row = oldSlice->rowStart; row < oldSlice->rowStop; ++row) + for (int row = oldSlice->row_start; row < oldSlice->row_stop; ++row) { - for (int col = oldSlice->colStart; col < oldSlice->colStop; ++col) + for (int col = oldSlice->col_start; col < oldSlice->col_stop; ++col) { rows.at(row).at(col) = nullptr; } @@ -415,9 +415,9 @@ void Grid::setElement(Slice *slice, GridElement *element) { }; - for (int row = slice->rowStart; row < slice->rowStop; ++row) + for (int row = slice->row_start; row < slice->row_stop; ++row) { - for (int col = slice->colStart; col < slice->colStop; ++col) + for (int col = slice->col_start; col < slice->col_stop; ++col) { oldElements.push_back(this->getElement(row, col)); rows.at(row).at(col) = element; @@ -436,55 +436,55 @@ void Grid::setElement(Slice *slice, GridElement *element) } } -void Grid::setElement(Slice *slice, grm_args_t *subplot_args) +void Grid::setElement(Slice *slice, grm_args_t *plot_args) { GridElement *element = nullptr; const char *grid_element_address = nullptr; - if (grm_args_values(subplot_args, "grid_element", "s", &grid_element_address)) + if (grm_args_values(plot_args, "grid_element", "s", &grid_element_address)) { element = reinterpret_cast(std::stoi(grid_element_address)); } else { element = new GridElement(); - element->subplot_args = subplot_args; + element->plot_args = plot_args; } std::stringstream address_stream; address_stream << element; - grm_args_push(subplot_args, "grid_element", "s", address_stream.str().c_str()); + grm_args_push(plot_args, "grid_element", "s", address_stream.str().c_str()); setElement(slice, element); } void Grid::printGrid() const { - double *subplot; + double *plot; for (int i = 0; i < nrows; i++) { for (int j = 0; j < ncols; j++) { - subplot = getElement(i, j)->subplot; - printf("[%f %f %f %f] ", subplot[0], subplot[1], subplot[2], subplot[3]); + plot = getElement(i, j)->plot; + printf("[%f %f %f %f] ", plot[0], plot[1], plot[2], plot[3]); } printf("\n"); } } -void Grid::finalizeSubplot() +void Grid::finalizePlot() { double xmin, xmax, ymin, ymax, rowHeight, elementWidth; int y, x, rowSpan, colSpan; GridElement *element; - if (!subplotSet) + if (!plot_set) { - setSubplot(0, 1, 0, 1); + setPlot(0, 1, 0, 1); } - GridElement::finalizeSubplot(); + GridElement::finalizePlot(); /* calculate height of each row */ std::vector rowHeights(nrows); - double totalHeightLeft = subplot[3] - subplot[2]; + double totalHeightLeft = plot[3] - plot[2]; int numRowsWithFlexibleHeight = 0; for (y = 0; y < nrows; y++) { @@ -492,13 +492,13 @@ void Grid::finalizeSubplot() for (x = 0; x < ncols; x++) { element = getElement(y, x); - if (element != nullptr && element->fitParentsHeight && element->absHeight != -1) + if (element != nullptr && element->fit_parents_height && element->abs_height != -1) { /* taking into account that an element can range over multiple rows */ rowSpan = this->getRowSpan(element); - if (element->absHeight / rowSpan > rowHeight) + if (element->abs_height / rowSpan > rowHeight) { - rowHeight = element->absHeight / rowSpan; + rowHeight = element->abs_height / rowSpan; } } } @@ -526,7 +526,7 @@ void Grid::finalizeSubplot() } /* calculate width of each column */ - double totalWidthLeft = subplot[1] - subplot[0]; + double totalWidthLeft = plot[1] - plot[0]; std::vector colWidths(ncols); int numColsWithFlexibleWidth = 0; for (x = 0; x < ncols; x++) @@ -535,13 +535,13 @@ void Grid::finalizeSubplot() for (y = 0; y < nrows; y++) { element = getElement(y, x); - if (element != nullptr && element->fitParentsWidth && element->absWidth != -1) + if (element != nullptr && element->fit_parents_width && element->abs_width != -1) { /* taking into account that an element can range over multiple columns */ colSpan = this->getColSpan(element); - if (element->absWidth / colSpan > colWidth) + if (element->abs_width / colSpan > colWidth) { - colWidth = element->absWidth / colSpan; + colWidth = element->abs_width / colSpan; } } } @@ -567,12 +567,12 @@ void Grid::finalizeSubplot() } } - /* calculate the subplot for each element */ - ymax = subplot[3]; + /* calculate the plot for each element */ + ymax = plot[3]; ymin = ymax; for (y = 0; y < nrows; y++) { - xmin = subplot[0]; + xmin = plot[0]; xmax = xmin; rowHeight = (rowHeights[y] == -1) ? totalHeightLeft / numRowsWithFlexibleHeight : rowHeights[y]; @@ -587,7 +587,7 @@ void Grid::finalizeSubplot() if (element != nullptr) { - element->setSubplot(xmin, xmax, ymin, ymax); + element->setPlot(xmin, xmax, ymin, ymax); } xmin = xmax; } @@ -602,7 +602,7 @@ void Grid::finalizeSubplot() element = getElement(y, x); if (element != nullptr) { - element->finalizeSubplot(); + element->finalizePlot(); } } } @@ -690,13 +690,13 @@ void Grid::trim() int Grid::getColSpan(GridElement *element) { Slice *slice = elementToPosition.at(element); - return slice->colStop - slice->colStart; + return slice->col_stop - slice->col_start; } int Grid::getRowSpan(GridElement *element) { Slice *slice = elementToPosition.at(element); - return slice->rowStop - slice->rowStart; + return slice->row_stop - slice->row_start; } int Grid::getNRows() const @@ -725,14 +725,14 @@ void Grid::ensureCellsAreGrid(Slice *slice) Grid *firstGridFound; GridElement *currentElement; int row, col; - int nrowsToAllocate = slice->rowStop; - int ncolsToAllocate = slice->colStop; + int nrowsToAllocate = slice->row_stop; + int ncolsToAllocate = slice->col_stop; this->upsize(nrowsToAllocate, ncolsToAllocate); - for (row = slice->rowStart; row < slice->rowStop; ++row) + for (row = slice->row_start; row < slice->row_stop; ++row) { - for (col = slice->colStart; col < slice->colStop; ++col) + for (col = slice->col_start; col < slice->col_stop; ++col) { currentElement = this->getElement(row, col); if (currentElement != nullptr && currentElement->isGrid()) diff --git a/lib/grm/src/grm/layout_c.cxx b/lib/grm/src/grm/layout_c.cxx index d30ff45de..f765534ae 100644 --- a/lib/grm/src/grm/layout_c.cxx +++ b/lib/grm/src/grm/layout_c.cxx @@ -153,7 +153,7 @@ void grid_finalize(grid_t *a_grid) { Grid *grid = reinterpret_cast(a_grid); - grid->finalizeSubplot(); + grid->finalizePlot(); } void trim(grid_t *a_grid) @@ -295,5 +295,5 @@ void element_setFitParentsWidth(element_t *a_element, int fitParentsWidth) void element_getSubplot(element_t *a_element, double **subplot) { GridElement *element = reinterpret_cast(a_element); - *subplot = element->getSubplot(); + *subplot = element->getPlot(); } diff --git a/lib/grm/src/grm/plot.cxx b/lib/grm/src/grm/plot.cxx index 4df58247c..130f59133 100644 --- a/lib/grm/src/grm/plot.cxx +++ b/lib/grm/src/grm/plot.cxx @@ -198,20 +198,23 @@ event_queue_t *event_queue = nullptr; /* ~~~~~~~~~~~~~~~~~~~~~~~~~ kind to fmt ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -static string_map_entry_t kind_to_fmt[] = {{"line", "xys"}, {"hexbin", "xys"}, - {"polar", "xys"}, {"shade", "xys"}, - {"stem", "xys"}, {"stairs", "xys"}, - {"contour", "xyzc"}, {"contourf", "xyzc"}, - {"tricontour", "xyzc"}, {"trisurface", "xyzc"}, - {"surface", "xyzc"}, {"wireframe", "xyzc"}, - {"plot3", "xyzc"}, {"scatter", "xyzc"}, - {"scatter3", "xyzc"}, {"quiver", "xyuv"}, - {"heatmap", "xyzc"}, {"hist", "x"}, - {"barplot", "y"}, {"isosurface", "c"}, - {"imshow", "c"}, {"nonuniformheatmap", "xyzc"}, - {"polar_histogram", "x"}, {"pie", "x"}, - {"volume", "c"}, {"marginal_heatmap", "xyzc"}, - {"polar_heatmap", "xyzc"}, {"nonuniformpolar_heatmap", "xyzc"}}; +static string_map_entry_t kind_to_fmt[] = { + {"line", "xys"}, {"hexbin", "xys"}, + {"polar_line", "xys"}, {"shade", "xys"}, + {"stem", "xys"}, {"stairs", "xys"}, + {"contour", "xyzc"}, {"contourf", "xyzc"}, + {"tricontour", "xyzc"}, {"trisurface", "xyzc"}, + {"surface", "xyzc"}, {"wireframe", "xyzc"}, + {"plot3", "xyzc"}, {"scatter", "xyzc"}, + {"scatter3", "xyzc"}, {"quiver", "xyuv"}, + {"heatmap", "xyzc"}, {"hist", "x"}, + {"barplot", "y"}, {"isosurface", "c"}, + {"imshow", "c"}, {"nonuniform_heatmap", "xyzc"}, + {"polar_histogram", "x"}, {"pie", "x"}, + {"volume", "c"}, {"marginal_heatmap", "xyzc"}, + {"polar_heatmap", "xyzc"}, {"nonuniform_polar_heatmap", "xyzc"}, + {"polar_scatter", "xys"}, +}; /* ~~~~~~~~~~~~~~~~~~~~~~~~~ kind to func ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ @@ -234,12 +237,13 @@ static plot_func_map_entry_t kind_to_func[] = {{"line", plot_line}, {"scatter3", plot_scatter3}, {"imshow", plot_imshow}, {"isosurface", plot_isosurface}, - {"polar", plot_polar}, + {"polar_line", plot_polar_line}, + {"polar_scatter", plot_polar_scatter}, {"trisurface", plot_trisurface}, {"tricontour", plot_tricontour}, {"shade", plot_shade}, - {"nonuniformheatmap", plot_heatmap}, - {"nonuniformpolar_heatmap", plot_polar_heatmap}, + {"nonuniform_heatmap", plot_heatmap}, + {"nonuniform_polar_heatmap", plot_polar_heatmap}, {"polar_histogram", plot_polar_histogram}, {"polar_heatmap", plot_polar_heatmap}, {"pie", plot_pie}, @@ -314,6 +318,7 @@ const char *valid_subplot_keys[] = {"abs_height", "ind_edge_color", "ind_edge_width", "keep_aspect_ratio", + "keep_radii_axes", "kind", "labels", "levels", @@ -328,7 +333,6 @@ const char *valid_subplot_keys[] = {"abs_height", "rel_width", "resample_method", "reset_ranges", - "rings", "rotation", "row", "row_span", @@ -350,6 +354,7 @@ const char *valid_subplot_keys[] = {"abs_height", "y_grid", "y_label", "y_lim", + "y_line_pos", "y_log", "y_ind", "z_flip", @@ -366,12 +371,14 @@ const char *valid_series_keys[] = {"a", "c", "c_dims", "c_range", + "clip_negative", "draw_edges", "d_min", "d_max", "edge_color", "edge_width", "error", + "error_bar_style", "face_color", "foreground_color", "indices", @@ -388,6 +395,7 @@ const char *valid_series_keys[] = {"a", "s", "step_where", "stairs", + "transparency", "u", "v", "weights", @@ -397,6 +405,7 @@ const char *valid_series_keys[] = {"a", "y", "y_colormap", "y_labels", + "y_line_pos", "y_range", "z", "z_dims", @@ -433,6 +442,7 @@ static string_map_entry_t key_to_formats[] = {{"a", "A"}, {"edge_color", "D|i"}, {"edge_width", "d"}, {"error", "a"}, + {"error_bar_style", "i"}, {"fig_size", "D"}, {"fit_parents_height", "i"}, {"fit_parents_width", "i"}, @@ -475,6 +485,7 @@ static string_map_entry_t key_to_formats[] = {{"a", "A"}, {"tilt", "d"}, {"title", "s"}, {"transformation", "i"}, + {"transparency", "d"}, {"u", "D"}, {"update", "i"}, {"v", "D"}, @@ -496,6 +507,7 @@ static string_map_entry_t key_to_formats[] = {{"a", "A"}, {"y_grid", "i"}, {"y_label", "s"}, {"y_lim", "D"}, + {"y_line_pos", "d"}, {"y_log", "i"}, {"y_ind", "i"}, {"y_range", "D"}, @@ -1082,7 +1094,7 @@ void plot_pre_plot(grm_args_t *plot_args) if (grm_args_values(plot_args, "clear", "i", &clear)) { logger((stderr, "Got keyword \"clear\" with value %d\n", clear)); - global_root->setAttribute("clear_ws", clear); + global_root->setAttribute("_clear_ws", clear); } if (grm_args_values(plot_args, "previous_pixel_size", "ii", &previous_pixel_width, &previous_pixel_height)) @@ -1116,11 +1128,11 @@ err_t plot_pre_subplot(grm_args_t *subplot_args) plot_process_font(subplot_args); plot_process_resample_method(subplot_args); - if (str_equals_any(kind, "polar", "polar_histogram")) + if (str_equals_any(kind, "polar_line", "polar_scatter", "polar_histogram")) { plot_draw_polar_axes(subplot_args); } - else if (!str_equals_any(kind, "pie", "polar_heatmap", "nonuniformpolar_heatmap")) + else if (!str_equals_any(kind, "pie", "polar_heatmap", "nonuniform_polar_heatmap")) { plot_draw_axes(subplot_args, 1); } @@ -1374,7 +1386,7 @@ err_t plot_store_coordinate_ranges(grm_args_t *subplot_args) } grm_args_values(subplot_args, "kind", "s", &kind); - group->setAttribute("kind", kind); + group->setAttribute("_kind", kind); if (grm_args_values(subplot_args, "x_lim", "dd", &x_min, &x_max)) { @@ -1409,7 +1421,7 @@ void plot_post_plot(grm_args_t *plot_args) if (grm_args_values(plot_args, "update", "i", &update)) { logger((stderr, "Got keyword \"update\" with value %d\n", update)); - global_root->setAttribute("update_ws", update); + global_root->setAttribute("_update_ws", update); } } @@ -1423,7 +1435,7 @@ void plot_post_subplot(grm_args_t *subplot_args) logger((stderr, "Got keyword \"kind\" with value \"%s\"\n", kind)); if (grm_args_contains(subplot_args, "labels")) { - if (str_equals_any(kind, "line", "stairs", "scatter", "stem")) + if (str_equals_any(kind, "line", "stairs", "scatter", "stem", "polar_line", "polar_scatter")) { plot_draw_legend(subplot_args); } @@ -1436,7 +1448,7 @@ void plot_post_subplot(grm_args_t *subplot_args) { plot_draw_axes(subplot_args, 2); } - else if (str_equals_any(kind, "polar_heatmap", "nonuniformpolar_heatmap")) + else if (str_equals_any(kind, "polar_heatmap", "nonuniform_polar_heatmap")) { plot_draw_polar_axes(subplot_args); } @@ -1640,6 +1652,7 @@ err_t plot_stairs(grm_args_t *subplot_args) unsigned int x_length, y_length; char *spec; const char *where; + double y_line_pos; auto subGroup = global_render->createSeries("stairs"); group->append(subGroup); @@ -1672,6 +1685,9 @@ err_t plot_stairs(grm_args_t *subplot_args) subGroup->setAttribute("y_range_max", y_max); } + if (grm_args_values(*current_series, "y_line_pos", "d", &y_line_pos)) + group->parentElement()->setAttribute("_y_line_pos", y_line_pos); + if (grm_args_values(*current_series, "line_spec", "s", &spec)) subGroup->setAttribute("line_spec", spec); if (grm_args_values(*current_series, "step_where", "s", &where)) subGroup->setAttribute("step_where", where); @@ -1841,7 +1857,7 @@ err_t plot_stem(grm_args_t *subplot_args) double *x, *y; unsigned int x_length, y_length; char *spec; - double y_min, y_max; + double y_min, y_max, y_line_pos; auto subGroup = global_render->createSeries("stem"); group->append(subGroup); @@ -1870,6 +1886,9 @@ err_t plot_stem(grm_args_t *subplot_args) subGroup->setAttribute("y_range_max", y_max); } + if (grm_args_values(*current_series, "y_line_pos", "d", &y_line_pos)) + group->parentElement()->setAttribute("_y_line_pos", y_line_pos); + if (grm_args_values(*current_series, "line_spec", "s", &spec)) subGroup->setAttribute("line_spec", spec); global_root->setAttribute("_id", ++id); @@ -1890,17 +1909,16 @@ err_t plot_hist(grm_args_t *subplot_args) (current_central_region_element) ? current_central_region_element : getCentralRegion(); grm_args_values(subplot_args, "series", "A", ¤t_series); - grm_args_values(subplot_args, "bar_color", "ddd", &bar_color_rgb[0], &bar_color_rgb[1], &bar_color_rgb[2]); - grm_args_values(subplot_args, "bar_color", "i", &bar_color_index); while (*current_series != nullptr) { int edge_color_index = 1; double edge_color_rgb[3] = {-1}; - double x_min, x_max, bar_width, y_min, y_max; + double x_min, x_max, bar_width, y_min, y_max, y_line_pos; double *bins, *x, *weights; unsigned int num_bins = 0, x_length, num_weights; char *orientation; + double transparency; auto subGroup = global_render->createSeries("hist"); group->append(subGroup); @@ -1909,17 +1927,24 @@ err_t plot_hist(grm_args_t *subplot_args) std::string str = std::to_string(id); auto context = global_render->getContext(); - std::vector bar_color_rgb_vec(bar_color_rgb, bar_color_rgb + 3); - (*context)["fill_color_rgb" + str] = bar_color_rgb_vec; - subGroup->setAttribute("fill_color_rgb", "fill_color_rgb" + str); - subGroup->setAttribute("fill_color_ind", bar_color_index); + if (grm_args_values(subplot_args, "bar_color", "ddd", &bar_color_rgb[0], &bar_color_rgb[1], &bar_color_rgb[2])) + { + std::vector bar_color_rgb_vec(bar_color_rgb, bar_color_rgb + 3); + (*context)["fill_color_rgb" + str] = bar_color_rgb_vec; + subGroup->setAttribute("fill_color_rgb", "fill_color_rgb" + str); + } + if (grm_args_values(subplot_args, "bar_color", "i", &bar_color_index)) + subGroup->setAttribute("fill_color_ind", bar_color_index); - grm_args_values(*current_series, "edge_color", "ddd", &edge_color_rgb[0], &edge_color_rgb[1], &edge_color_rgb[2]); - grm_args_values(*current_series, "edge_color", "i", &edge_color_index); - std::vector edge_color_rgb_vec(edge_color_rgb, edge_color_rgb + 3); - (*context)["line_color_rgb" + str] = edge_color_rgb_vec; - subGroup->setAttribute("line_color_rgb", "line_color_rgb" + str); - subGroup->setAttribute("line_color_ind", edge_color_index); + if (grm_args_values(*current_series, "edge_color", "ddd", &edge_color_rgb[0], &edge_color_rgb[1], + &edge_color_rgb[2])) + { + std::vector edge_color_rgb_vec(edge_color_rgb, edge_color_rgb + 3); + (*context)["line_color_rgb" + str] = edge_color_rgb_vec; + subGroup->setAttribute("line_color_rgb", "line_color_rgb" + str); + } + if (grm_args_values(*current_series, "edge_color", "i", &edge_color_index)) + subGroup->setAttribute("line_color_ind", edge_color_index); if (grm_args_first_value(*current_series, "bins", "D", &bins, &num_bins)) { @@ -1948,6 +1973,14 @@ err_t plot_hist(grm_args_t *subplot_args) subGroup->setAttribute("y_range_max", y_max); } + if (grm_args_values(*current_series, "y_line_pos", "d", &y_line_pos)) + group->parentElement()->setAttribute("_y_line_pos", y_line_pos); + + if (grm_args_values(*current_series, "transparency", "d", &transparency)) + { + subGroup->setAttribute("transparency", transparency); + } + grm_args_first_value(*current_series, "x", "D", &x, &x_length); std::vector x_vec(x, x + x_length); (*context)["x" + str] = x_vec; @@ -2012,7 +2045,8 @@ err_t plot_barplot(grm_args_t *subplot_args) unsigned int y_labels_length = 0; std::vector c_vec; std::vector c_rgb_vec; - double x_min, x_max, y_min, y_max; + double x_min, x_max, y_min, y_max, y_line_pos; + double transparency; auto subGroup = global_render->createSeries("barplot"); group->append(subGroup); @@ -2041,6 +2075,10 @@ err_t plot_barplot(grm_args_t *subplot_args) { subGroup->setAttribute("orientation", orientation); } + if (grm_args_values(*current_series, "transparency", "d", &transparency)) + { + subGroup->setAttribute("transparency", transparency); + } /* Push attributes on the series level to the tree */ if (grm_args_values(*current_series, "edge_color", "ddd", &edge_color_rgb[0], &edge_color_rgb[1], @@ -2068,6 +2106,8 @@ err_t plot_barplot(grm_args_t *subplot_args) subGroup->setAttribute("y_range_min", y_min); subGroup->setAttribute("y_range_max", y_max); } + if (grm_args_values(*current_series, "y_line_pos", "d", &y_line_pos)) + group->parentElement()->setAttribute("_y_line_pos", y_line_pos); if (grm_args_first_value(*current_series, "y_labels", "S", &y_labels, &y_labels_length)) { std::vector y_labels_vec(y_labels, y_labels + y_labels_length); @@ -2603,11 +2643,7 @@ err_t plot_heatmap(grm_args_t *subplot_args) ++current_series; } - if (strcmp(kind, "marginal_heatmap") != 0) - { - plot_draw_colorbar(subplot_args, 0.0, 256); - } - + if (strcmp(kind, "marginal_heatmap") != 0) plot_draw_colorbar(subplot_args, 0.0, 256); return error; } @@ -3137,7 +3173,7 @@ err_t plot_volume(grm_args_t *subplot_args) return ERROR_NONE; } -err_t plot_polar(grm_args_t *subplot_args) +err_t plot_polar_line(grm_args_t *subplot_args) { grm_args_t **current_series; @@ -3148,9 +3184,11 @@ err_t plot_polar(grm_args_t *subplot_args) while (*current_series != nullptr) { double *rho, *theta; + double y_min, y_max, x_min, x_max; unsigned int rho_length, theta_length; char *spec; - auto subGroup = global_render->createSeries("polar"); + auto subGroup = global_render->createSeries("polar_line"); + int clip_negative = 0, marker_type; group->append(subGroup); grm_args_first_value(*current_series, "x", "D", &theta, &theta_length); @@ -3168,9 +3206,83 @@ err_t plot_polar(grm_args_t *subplot_args) (*context)["y" + str] = rho_vec; subGroup->setAttribute("y", "y" + str); + if (grm_args_values(*current_series, "y_range", "dd", &y_min, &y_max)) + { + subGroup->setAttribute("y_range_min", y_min); + subGroup->setAttribute("y_range_max", y_max); + } + if (grm_args_values(*current_series, "x_range", "dd", &x_min, &x_max)) + { + subGroup->setAttribute("x_range_min", x_min); + subGroup->setAttribute("x_range_max", x_max); + } + if (grm_args_values(*current_series, "clip_negative", "i", &clip_negative)) + { + subGroup->setAttribute("clip_negative", clip_negative); + } + if (grm_args_values(*current_series, "line_spec", "s", &spec)) subGroup->setAttribute("line_spec", spec); + if (grm_args_values(*current_series, "marker_type", "i", &marker_type)) + subGroup->setAttribute("marker_type", marker_type); - global_root->setAttribute("_id", id++); + global_root->setAttribute("_id", ++id); + ++current_series; + } + + return ERROR_NONE; +} + +err_t plot_polar_scatter(grm_args_t *subplot_args) +{ + grm_args_t **current_series; + + std::shared_ptr group = + (current_central_region_element) ? current_central_region_element : getCentralRegion(); + + grm_args_values(subplot_args, "series", "A", ¤t_series); + while (*current_series != nullptr) + { + double *rho, *theta; + double y_min, y_max, x_min, x_max; + unsigned int rho_length, theta_length; + auto sub_group = global_render->createSeries("polar_scatter"); + int clip_negative = 0, marker_type; + group->append(sub_group); + + grm_args_first_value(*current_series, "x", "D", &theta, &theta_length); + grm_args_first_value(*current_series, "y", "D", &rho, &rho_length); + + int id = static_cast(global_root->getAttribute("_id")); + std::string str = std::to_string(id); + auto context = global_render->getContext(); + + std::vector theta_vec(theta, theta + theta_length); + std::vector rho_vec(rho, rho + rho_length); + + (*context)["x" + str] = theta_vec; + sub_group->setAttribute("x", "x" + str); + (*context)["y" + str] = rho_vec; + sub_group->setAttribute("y", "y" + str); + + if (grm_args_values(*current_series, "y_range", "dd", &y_min, &y_max)) + { + sub_group->setAttribute("y_range_min", y_min); + sub_group->setAttribute("y_range_max", y_max); + } + if (grm_args_values(*current_series, "x_range", "dd", &x_min, &x_max)) + { + sub_group->setAttribute("x_range_min", x_min); + sub_group->setAttribute("x_range_max", x_max); + } + if (grm_args_values(*current_series, "clip_negative", "i", &clip_negative)) + { + sub_group->setAttribute("clip_negative", clip_negative); + } + + if (grm_args_values(*current_series, "marker_type", "i", &marker_type)) + sub_group->setAttribute("marker_type", marker_type); + + global_root->setAttribute("_id", ++id); ++current_series; } @@ -3230,7 +3342,7 @@ err_t plot_polar(grm_args_t *subplot_args) * It is not compatible nbins or bin_edges. * \param[in] num_bins an int setting the number of bins (series) * It is not compatible with bin_edges, nbins or bin_counts. - * \param[in] face_alpha double value between 0.0 and 1.0 inclusive (series) + * \param[in] transparency double value between 0.0 and 1.0 inclusive (series) * Sets the opacity of bins. * A value of 1.0 means fully opaque and 0.0 means completely transparent (invisible). * The default value is 0.75. @@ -3247,8 +3359,11 @@ err_t plot_polar_histogram(grm_args_t *subplot_args) double *r_lim = nullptr; unsigned int dummy; int stairs; + int keep_radii_axes; int x_colormap, y_colormap; - int draw_edges, phi_flip, edge_color, face_color, face_alpha; + int draw_edges, phi_flip, edge_color, face_color; + double transparency; + double xrange_min, xrange_max, ylim_min, ylim_max; grm_args_t **series; std::shared_ptr plot_group = edit_figure->lastChildElement(); @@ -3279,10 +3394,10 @@ err_t plot_polar_histogram(grm_args_t *subplot_args) series_group->setAttribute("color_ind", face_color); } - /* face_alpha */ - if (grm_args_values(*series, "face_alpha", "d", &face_alpha)) + /* transparency */ + if (grm_args_values(*series, "transparency", "d", &transparency)) { - series_group->setAttribute("face_alpha", face_alpha); + series_group->setAttribute("transparency", transparency); } if (grm_args_values(subplot_args, "phi_flip", "i", &phi_flip)) @@ -3290,6 +3405,11 @@ err_t plot_polar_histogram(grm_args_t *subplot_args) plot_group->setAttribute("phi_flip", phi_flip); } + if (grm_args_values(subplot_args, "keep_radii_axes", "i", &keep_radii_axes)) + { + plot_group->setAttribute("keep_radii_axes", keep_radii_axes); + } + if (grm_args_values(*series, "draw_edges", "i", &draw_edges)) { series_group->setAttribute("draw_edges", draw_edges); @@ -3306,6 +3426,18 @@ err_t plot_polar_histogram(grm_args_t *subplot_args) plot_group->setAttribute("r_lim_max", r_lim[1]); } + if (grm_args_values(subplot_args, "y_lim", "dd", &ylim_min, &ylim_max)) + { + plot_group->setAttribute("y_lim_min", ylim_min); + plot_group->setAttribute("y_lim_max", ylim_max); + } + + if (grm_args_values(*series, "x_range", "dd", &xrange_min, &xrange_max)) + { + series_group->setAttribute("x_range_min", xrange_min); + series_group->setAttribute("x_range_max", xrange_max); + } + if (grm_args_values(*series, "x_colormap", "i", &x_colormap)) { series_group->setAttribute("x_colormap", x_colormap); @@ -3569,10 +3701,10 @@ err_t plot_raw(grm_args_t *plot_args) graphics_data = base64_decode(nullptr, base64_data, nullptr, &error); cleanup_if_error; - global_root->setAttribute("clear_ws", 1); + global_root->setAttribute("_clear_ws", 1); data_vec = std::vector(graphics_data, graphics_data + strlen(graphics_data)); edit_figure->append(global_render->createDrawGraphics("graphics", data_vec)); - global_root->setAttribute("update_ws", 1); + global_root->setAttribute("_update_ws", 1); cleanup: if (graphics_data != nullptr) @@ -3748,7 +3880,10 @@ err_t plot_draw_axes(grm_args_t *args, unsigned int pass) int tick_color; tick_color = *reinterpret_cast(tick_arg->value_ptr); - (*tick_modification_map)[axis_id][tick_value].emplace("line_color_ind", tick_color); + if ((*tick_modification_map)[axis_id][tick_value].count("line_color_ind") > 0) + (*tick_modification_map)[axis_id][tick_value]["line_color_ind"] = GRM::Value(tick_color); + else + (*tick_modification_map)[axis_id][tick_value].emplace("line_color_ind", tick_color); logger((stderr, "Got tick_color \"%i\"\n", tick_color)); } else if (strcmp(tick_arg->key, "line_spec") == 0) @@ -3762,35 +3897,11 @@ err_t plot_draw_axes(grm_args_t *args, unsigned int pass) const char *line_spec; line_spec = *reinterpret_cast(tick_arg->value_ptr); - (*tick_modification_map)[axis_id][tick_value].emplace("line_spec", std::string(line_spec)); - logger((stderr, "Got line_spec \"%s\"\n", line_spec)); - } - else if (strcmp(tick_arg->key, "line_type") == 0) - { - if (str_equals_any(tick_arg->value_format, "s", "i") != 0) - { - logger((stderr, - "Invalid value format \"%s\" for axis modification \"%s\", expected \"s\" or " - "\"i\"\n", - tick_arg->value_format, tick_arg->key)); - continue; - } - if (strcmp(tick_arg->value_format, "s") == 0) - { - const char *line_type; - line_type = *reinterpret_cast(tick_arg->value_ptr); - - (*tick_modification_map)[axis_id][tick_value].emplace("line_type", std::string(line_type)); - logger((stderr, "Got line_type \"%s\"\n", line_type)); - } + if ((*tick_modification_map)[axis_id][tick_value].count("line_spec") > 0) + (*tick_modification_map)[axis_id][tick_value]["line_spec"] = GRM::Value(line_spec); else - { - int line_type; - line_type = *reinterpret_cast(tick_arg->value_ptr); - - (*tick_modification_map)[axis_id][tick_value].emplace("line_type", line_type); - logger((stderr, "Got line_type \"%i\"\n", line_type)); - } + (*tick_modification_map)[axis_id][tick_value].emplace("line_spec", line_spec); + logger((stderr, "Got line_spec \"%s\"\n", line_spec)); } else if (strcmp(tick_arg->key, "tick_length") == 0) { @@ -3802,12 +3913,16 @@ err_t plot_draw_axes(grm_args_t *args, unsigned int pass) } double tick_length; tick_length = *reinterpret_cast(tick_arg->value_ptr); - (*tick_modification_map)[axis_id][tick_value].emplace("tick_size", tick_length); + + if ((*tick_modification_map)[axis_id][tick_value].count("tick_size") > 0) + (*tick_modification_map)[axis_id][tick_value]["tick_size"] = GRM::Value(tick_length); + else + (*tick_modification_map)[axis_id][tick_value].emplace("tick_size", tick_length); logger((stderr, "Got tick_length \"%lf\"\n", tick_length)); } else if (strcmp(tick_arg->key, "text_align_horizontal") == 0) { - if (str_equals_any(tick_arg->value_format, "s", "i") != 0) + if (!str_equals_any(tick_arg->value_format, "s", "i")) { logger((stderr, "Invalid value format \"%s\" for axis modification \"%s\", expected \"s\" or " @@ -3820,8 +3935,12 @@ err_t plot_draw_axes(grm_args_t *args, unsigned int pass) const char *text_align_horizontal; text_align_horizontal = *reinterpret_cast(tick_arg->value_ptr); - (*tick_modification_map)[axis_id][tick_value].emplace("text_align_horizontal", - std::string(text_align_horizontal)); + if ((*tick_modification_map)[axis_id][tick_value].count("text_align_horizontal") > 0) + (*tick_modification_map)[axis_id][tick_value]["text_align_horizontal"] = + GRM::Value(text_align_horizontal); + else + (*tick_modification_map)[axis_id][tick_value].emplace("text_align_horizontal", + text_align_horizontal); logger((stderr, "Got text_align_horizontal \"%s\"\n", text_align_horizontal)); } else @@ -3829,14 +3948,18 @@ err_t plot_draw_axes(grm_args_t *args, unsigned int pass) int text_align_horizontal; text_align_horizontal = *reinterpret_cast(tick_arg->value_ptr); - (*tick_modification_map)[axis_id][tick_value].emplace("text_align_horizontal", - text_align_horizontal); + if ((*tick_modification_map)[axis_id][tick_value].count("text_align_horizontal") > 0) + (*tick_modification_map)[axis_id][tick_value]["text_align_horizontal"] = + GRM::Value(text_align_horizontal); + else + (*tick_modification_map)[axis_id][tick_value].emplace("text_align_horizontal", + text_align_horizontal); logger((stderr, "Got text_align_horizontal \"%i\"\n", text_align_horizontal)); } } else if (strcmp(tick_arg->key, "text_align_vertical") == 0) { - if (str_equals_any(tick_arg->value_format, "s", "i") != 0) + if (!str_equals_any(tick_arg->value_format, "s", "i")) { logger((stderr, "Invalid value format \"%s\" for axis modification \"%s\", expected \"s\" or " @@ -3849,8 +3972,12 @@ err_t plot_draw_axes(grm_args_t *args, unsigned int pass) const char *text_align_vertical; text_align_vertical = *reinterpret_cast(tick_arg->value_ptr); - (*tick_modification_map)[axis_id][tick_value].emplace("text_align_vertical", - std::string(text_align_vertical)); + if ((*tick_modification_map)[axis_id][tick_value].count("text_align_vertical") > 0) + (*tick_modification_map)[axis_id][tick_value]["text_align_vertical"] = + GRM::Value(text_align_vertical); + else + (*tick_modification_map)[axis_id][tick_value].emplace("text_align_vertical", + text_align_vertical); logger((stderr, "Got text_align_vertical \"%s\"\n", text_align_vertical)); } else @@ -3858,8 +3985,12 @@ err_t plot_draw_axes(grm_args_t *args, unsigned int pass) int text_align_vertical; text_align_vertical = *reinterpret_cast(tick_arg->value_ptr); - (*tick_modification_map)[axis_id][tick_value].emplace("text_align_vertical", - text_align_vertical); + if ((*tick_modification_map)[axis_id][tick_value].count("text_align_vertical") > 0) + (*tick_modification_map)[axis_id][tick_value]["text_align_vertical"] = + GRM::Value(text_align_vertical); + else + (*tick_modification_map)[axis_id][tick_value].emplace("text_align_vertical", + text_align_vertical); logger((stderr, "Got text_align_vertical \"%i\"\n", text_align_vertical)); } } @@ -3874,7 +4005,10 @@ err_t plot_draw_axes(grm_args_t *args, unsigned int pass) const char *tick_label; tick_label = *reinterpret_cast(tick_arg->value_ptr); - (*tick_modification_map)[axis_id][tick_value].emplace("tick_label", std::string(tick_label)); + if ((*tick_modification_map)[axis_id][tick_value].count("tick_label") > 0) + (*tick_modification_map)[axis_id][tick_value]["tick_label"] = GRM::Value(tick_label); + else + (*tick_modification_map)[axis_id][tick_value].emplace("tick_label", tick_label); logger((stderr, "Got tick_label \"%s\"\n", tick_label)); } else if (strcmp(tick_arg->key, "tick_width") == 0) @@ -3888,7 +4022,10 @@ err_t plot_draw_axes(grm_args_t *args, unsigned int pass) double tick_width; tick_width = *reinterpret_cast(tick_arg->value_ptr); - (*tick_modification_map)[axis_id][tick_value].emplace("tick_size", tick_width); + if ((*tick_modification_map)[axis_id][tick_value].count("tick_width") > 0) + (*tick_modification_map)[axis_id][tick_value]["tick_width"] = GRM::Value(tick_width); + else + (*tick_modification_map)[axis_id][tick_value].emplace("tick_width", tick_width); logger((stderr, "Got tick_width \"%lf\"\n", tick_width)); } else if (strcmp(tick_arg->key, "new_tick_value") == 0) @@ -3902,7 +4039,10 @@ err_t plot_draw_axes(grm_args_t *args, unsigned int pass) double new_tick_value; new_tick_value = *reinterpret_cast(tick_arg->value_ptr); - (*tick_modification_map)[axis_id][tick_value].emplace("value", new_tick_value); + if ((*tick_modification_map)[axis_id][tick_value].count("value") > 0) + (*tick_modification_map)[axis_id][tick_value]["value"] = GRM::Value(new_tick_value); + else + (*tick_modification_map)[axis_id][tick_value].emplace("value", new_tick_value); logger((stderr, "Got new_tick_value \"%lf\"\n", new_tick_value)); } else if (strcmp(tick_arg->key, "tick_is_major") == 0) @@ -3916,7 +4056,10 @@ err_t plot_draw_axes(grm_args_t *args, unsigned int pass) int tick_is_major; tick_is_major = *reinterpret_cast(tick_arg->value_ptr); - (*tick_modification_map)[axis_id][tick_value].emplace("is_major", tick_is_major); + if ((*tick_modification_map)[axis_id][tick_value].count("is_major") > 0) + (*tick_modification_map)[axis_id][tick_value]["is_major"] = GRM::Value(tick_is_major); + else + (*tick_modification_map)[axis_id][tick_value].emplace("is_major", tick_is_major); logger((stderr, "Got tick_is_major \"%i\"\n", tick_is_major)); } else if (strcmp(tick_arg->key, "tick_label_color") == 0) @@ -3930,12 +4073,15 @@ err_t plot_draw_axes(grm_args_t *args, unsigned int pass) int tick_label_color; tick_label_color = *reinterpret_cast(tick_arg->value_ptr); - (*tick_modification_map)[axis_id][tick_value].emplace("text_color_ind", tick_label_color); + if ((*tick_modification_map)[axis_id][tick_value].count("text_color_ind") > 0) + (*tick_modification_map)[axis_id][tick_value]["text_color_ind"] = GRM::Value(tick_label_color); + else + (*tick_modification_map)[axis_id][tick_value].emplace("text_color_ind", tick_label_color); logger((stderr, "Got tick_label_color \"%i\"\n", tick_label_color)); } else if (strcmp(tick_arg->key, "font") == 0) { - if (str_equals_any(tick_arg->value_format, "s", "i") != 0) + if (!str_equals_any(tick_arg->value_format, "s", "i")) { logger((stderr, "Invalid value format \"%s\" for axis modification \"%s\", expected \"s\" or " @@ -3948,7 +4094,10 @@ err_t plot_draw_axes(grm_args_t *args, unsigned int pass) const char *font; font = *reinterpret_cast(tick_arg->value_ptr); - (*tick_modification_map)[axis_id][tick_value].emplace("font", std::string(font)); + if ((*tick_modification_map)[axis_id][tick_value].count("font") > 0) + (*tick_modification_map)[axis_id][tick_value]["font"] = GRM::Value(font); + else + (*tick_modification_map)[axis_id][tick_value].emplace("font", font); logger((stderr, "Got font \"%s\"\n", font)); } else @@ -3956,13 +4105,16 @@ err_t plot_draw_axes(grm_args_t *args, unsigned int pass) int font; font = *reinterpret_cast(tick_arg->value_ptr); - (*tick_modification_map)[axis_id][tick_value].emplace("font", font); + if ((*tick_modification_map)[axis_id][tick_value].count("font") > 0) + (*tick_modification_map)[axis_id][tick_value]["font"] = GRM::Value(font); + else + (*tick_modification_map)[axis_id][tick_value].emplace("font", font); logger((stderr, "Got font \"%i\"\n", font)); } } else if (strcmp(tick_arg->key, "font_precision") == 0) { - if (str_equals_any(tick_arg->value_format, "s", "i") != 0) + if (!str_equals_any(tick_arg->value_format, "s", "i")) { logger((stderr, "Invalid value format \"%s\" for axis modification \"%s\", expected \"s\" or " @@ -3975,8 +4127,11 @@ err_t plot_draw_axes(grm_args_t *args, unsigned int pass) const char *font_precision; font_precision = *reinterpret_cast(tick_arg->value_ptr); - (*tick_modification_map)[axis_id][tick_value].emplace("font_precision", - std::string(font_precision)); + if ((*tick_modification_map)[axis_id][tick_value].count("font_precision") > 0) + (*tick_modification_map)[axis_id][tick_value]["font_precision"] = + GRM::Value(font_precision); + else + (*tick_modification_map)[axis_id][tick_value].emplace("font_precision", font_precision); logger((stderr, "Got font_precision \"%s\"\n", font_precision)); } else @@ -3984,7 +4139,11 @@ err_t plot_draw_axes(grm_args_t *args, unsigned int pass) int font_precision; font_precision = *reinterpret_cast(tick_arg->value_ptr); - (*tick_modification_map)[axis_id][tick_value].emplace("font_precision", font_precision); + if ((*tick_modification_map)[axis_id][tick_value].count("font_precision") > 0) + (*tick_modification_map)[axis_id][tick_value]["font_precision"] = + GRM::Value(font_precision); + else + (*tick_modification_map)[axis_id][tick_value].emplace("font_precision", font_precision); logger((stderr, "Got font_precision \"%i\"\n", font_precision)); } } @@ -3999,7 +4158,11 @@ err_t plot_draw_axes(grm_args_t *args, unsigned int pass) int scientific_format; scientific_format = *reinterpret_cast(tick_arg->value_ptr); - (*tick_modification_map)[axis_id][tick_value].emplace("scientific_format", scientific_format); + if ((*tick_modification_map)[axis_id][tick_value].count("scientific_format") > 0) + (*tick_modification_map)[axis_id][tick_value]["scientific_format"] = + GRM::Value(scientific_format); + else + (*tick_modification_map)[axis_id][tick_value].emplace("scientific_format", scientific_format); logger((stderr, "Got scientific_format \"%i\"\n", scientific_format)); } else @@ -4088,8 +4251,8 @@ err_t plot_draw_legend(grm_args_t *subplot_args) int id = static_cast(global_root->getAttribute("_id")); global_root->setAttribute("_id", ++id); - std::string labels_key = std::to_string(id) + "labels"; - std::string specs_key = std::to_string(id) + "specs"; + std::string labels_key = "labels" + std::to_string(id); + std::string specs_key = "specs" + std::to_string(id); std::vector labels_vec(labels, labels + num_labels); std::vector specs_vec; @@ -4236,6 +4399,7 @@ err_t plot_draw_error_bars(grm_args_t *series_args, unsigned int x_length) grm_args_t *error_container; arg_t *arg_ptr; err_t error; + int error_bar_style; double *absolute_upwards = nullptr, *absolute_downwards = nullptr, *relative_upwards = nullptr, *relative_downwards = nullptr; @@ -4318,6 +4482,11 @@ err_t plot_draw_error_bars(grm_args_t *series_args, unsigned int x_length) if (absolute_upwards_flt != FLT_MAX) subGroup->setAttribute("absolute_upwards_flt", absolute_upwards_flt); if (relative_upwards_flt != FLT_MAX) subGroup->setAttribute("relative_upwards_flt", relative_upwards_flt); + if (grm_args_values(series_args, "error_bar_style", "i", &error_bar_style)) + { + subGroup->setAttribute("error_bar_style", error_bar_style); + } + if (error_container != nullptr) { if (grm_args_values(error_container, "upwards_cap_color", "i", &color_upwards_cap)) @@ -6145,7 +6314,7 @@ int plot_process_subplot_args(grm_args_t *subplot_args) std::shared_ptr group = (current_dom_element) ? current_dom_element : edit_figure->lastChildElement(); grm_args_values(subplot_args, "kind", "s", &kind); - group->setAttribute("kind", kind); + group->setAttribute("_kind", kind); logger((stderr, "Got keyword \"kind\" with value \"%s\"\n", kind)); if (plot_pre_subplot(subplot_args) != ERROR_NONE) @@ -6263,14 +6432,14 @@ int grm_plot(const grm_args_t *args) // TODO: rename this method so the name dis } /* check if given figure_id (even default 0) already exists in the render */ - auto figure_element = global_root->querySelectors("[figure_id=figure" + std::to_string(figure_id) + "]"); + auto figure_element = global_root->querySelectors("[_figure_id=figure" + std::to_string(figure_id) + "]"); auto last_figure = global_root->hasChildNodes() ? global_root->children().back() : nullptr; if (append_figures && !figure_id_given) { if (last_figure != nullptr && !last_figure->hasChildNodes()) { - auto figure_id_str = static_cast(last_figure->getAttribute("figure_id")); + auto figure_id_str = static_cast(last_figure->getAttribute("_figure_id")); figure_id = std::stoi(figure_id_str.substr(6)); // Remove a `figure` prefix before converting last_figure->remove(); } @@ -6281,14 +6450,14 @@ int grm_plot(const grm_args_t *args) // TODO: rename this method so the name dis } edit_figure = global_render->createElement("figure"); global_root->append(edit_figure); - edit_figure->setAttribute("figure_id", "figure" + std::to_string(figure_id)); + edit_figure->setAttribute("_figure_id", "figure" + std::to_string(figure_id)); } else { if (figure_element != nullptr) figure_element->remove(); edit_figure = global_render->createElement("figure"); global_root->append(edit_figure); - edit_figure->setAttribute("figure_id", "figure" + std::to_string(figure_id)); + edit_figure->setAttribute("_figure_id", "figure" + std::to_string(figure_id)); } current_dom_element = nullptr; current_central_region_element = nullptr; @@ -6435,7 +6604,7 @@ int grm_plot(const grm_args_t *args) // TODO: rename this method so the name dis } plot_post_plot(edit_plot_args); } - edit_figure = global_root->querySelectors("[figure_id=figure" + std::to_string(active_plot_index - 1) + "]"); + edit_figure = global_root->querySelectors("[_figure_id=figure" + std::to_string(active_plot_index - 1) + "]"); global_render->setActiveFigure(edit_figure); global_render->render(); global_render->setAutoUpdate(true); @@ -6502,7 +6671,7 @@ int grm_switch(unsigned int id) grm_args_t **args_array = nullptr; unsigned int args_array_length = 0; - auto figure_element = global_root->querySelectors("[figure_id=figure" + std::to_string(id) + "]"); + auto figure_element = global_root->querySelectors("[_figure_id=figure" + std::to_string(id) + "]"); if (figure_element == nullptr) { /* it is a new figure_id, but only with grm_switch will it be really active @@ -6513,7 +6682,7 @@ int grm_switch(unsigned int id) global_root->append(edit_figure); global_render->getAutoUpdate(&auto_update); global_render->setAutoUpdate(false); - edit_figure->setAttribute("figure_id", "figure" + std::to_string(id)); + edit_figure->setAttribute("_figure_id", "figure" + std::to_string(id)); global_render->setAutoUpdate(auto_update); global_render->setActiveFigure(edit_figure); } @@ -6686,7 +6855,7 @@ int grm_plot_helper(grm::GridElement *gridElement, grm::Slice *slice, if (!gridElement->isGrid()) { - grm_args_t **current_subplot_args = &gridElement->subplot_args; + grm_args_t **current_subplot_args = &gridElement->plot_args; auto layoutGridElement = global_render->createLayoutGridElement(*gridElement, *slice); parentDomElement->append(layoutGridElement); auto plot = global_render->createPlot(plotId); @@ -6703,10 +6872,10 @@ int grm_plot_helper(grm::GridElement *gridElement, grm::Slice *slice, auto *currentGrid = reinterpret_cast(gridElement); auto gridDomElement = global_render->createLayoutGrid(*currentGrid); - gridDomElement->setAttribute("start_row", slice->rowStart); - gridDomElement->setAttribute("stop_row", slice->rowStop); - gridDomElement->setAttribute("start_col", slice->colStart); - gridDomElement->setAttribute("stop_col", slice->colStop); + gridDomElement->setAttribute("start_row", slice->row_start); + gridDomElement->setAttribute("stop_row", slice->row_stop); + gridDomElement->setAttribute("start_col", slice->col_start); + gridDomElement->setAttribute("stop_col", slice->col_stop); parentDomElement->append(gridDomElement); if (!grm_iterate_grid(currentGrid, gridDomElement, plotId)) return 0; @@ -6729,7 +6898,7 @@ int get_free_id_from_figure_elements() std::vector given_ids; for (auto &fig : global_root->children()) { - given_ids.push_back(static_cast(fig->getAttribute("figure_id"))); + given_ids.push_back(static_cast(fig->getAttribute("_figure_id"))); } int free_id = 0; while (true) @@ -6922,3 +7091,36 @@ int get_focus_and_factor_from_dom(const int x1, const int y1, const int x2, cons *focus_y = (ndc_top - *factor_y * viewport[3]) / (1 - *factor_y) - (viewport[2] + viewport[3]) / 2.0; return 1; } + +std::map> grm_get_context_data() +{ + std::map> context_data; + auto context = global_render->getContext(); + for (auto item : *context) + { + std::visit( + GRM::overloaded{ + [&context_data](std::reference_wrapper>> pair_ref) { + for (int row = 0; row < pair_ref.get().second.size(); row++) + { + context_data[pair_ref.get().first.c_str()].emplace_back( + std::to_string(pair_ref.get().second.data()[row])); + } + }, + [&context_data](std::reference_wrapper>> pair_ref) { + for (int row = 0; row < pair_ref.get().second.size(); row++) + { + context_data[pair_ref.get().first.c_str()].emplace_back( + std::to_string(pair_ref.get().second.data()[row])); + } + }, + [&context_data](std::reference_wrapper>> pair_ref) { + for (int row = 0; row < pair_ref.get().second.size(); row++) + { + context_data[pair_ref.get().first.c_str()].emplace_back(pair_ref.get().second.data()[row]); + } + }}, + item); + } + return context_data; +} diff --git a/lib/grm/src/grm/plot_int.h b/lib/grm/src/grm/plot_int.h index 10fa20629..ce14cdfe7 100644 --- a/lib/grm/src/grm/plot_int.h +++ b/lib/grm/src/grm/plot_int.h @@ -149,8 +149,9 @@ err_t plot_scatter3(grm_args_t *subplot_args); err_t plot_imshow(grm_args_t *subplot_args); err_t plot_isosurface(grm_args_t *subplot_args); err_t plot_volume(grm_args_t *subplot_args); -err_t plot_polar(grm_args_t *subplot_args); +err_t plot_polar_line(grm_args_t *subplot_args); err_t plot_polar_histogram(grm_args_t *subplot_args); +err_t plot_polar_scatter(grm_args_t *subplot_args); err_t plot_pie(grm_args_t *subplot_args); err_t plot_trisurface(grm_args_t *subplot_args); err_t plot_tricontour(grm_args_t *subplot_args); diff --git a/lib/grm/test/internal_api/grm/bson_serialize_deserialize.c b/lib/grm/test/internal_api/grm/bson_serialize_deserialize.c index 3a8d96c4a..a40ccdadc 100644 --- a/lib/grm/test/internal_api/grm/bson_serialize_deserialize.c +++ b/lib/grm/test/internal_api/grm/bson_serialize_deserialize.c @@ -1,11 +1,15 @@ +#ifdef __unix__ #define _POSIX_C_SOURCE 200809L #define _XOPEN_SOURCE 500 +#endif #include #include #include #include +#include #include +#include "grm/bson_int.h" #include "grm/memwriter_int.h" diff --git a/lib/grm/test/public_api/grm/snoop/snoop.c b/lib/grm/test/public_api/grm/snoop/snoop.c index 7d4926b3b..3575af138 100644 --- a/lib/grm/test/public_api/grm/snoop/snoop.c +++ b/lib/grm/test/public_api/grm/snoop/snoop.c @@ -378,7 +378,7 @@ static int test_polar(void) /* TODO: Support `angles` and `radii` names in GRM! */ grm_args_push(args, "x", "nD", n, angles); grm_args_push(args, "y", "nD", n, radii); - grm_args_push(args, "kind", "s", "polar"); + grm_args_push(args, "kind", "s", "polar_line"); grm_args_push(args, "size", "ii", PLOT_WIDTH, PLOT_HEIGHT); was_successful = grm_plot(args);