NEW: JKQTPXYGraphLabels which can draw a label next to each datapoint in the given x/y-dataset. The labels can be x-/y- or x&y-coordinates or custom, then defined by a user-supplied functor (+example \ref JKQTPlotterGraphLabels)

This commit is contained in:
jkriege2 2024-02-06 14:49:14 +01:00
parent 0009ff8f64
commit 3c9bd56d9e
42 changed files with 1931 additions and 28 deletions

12
.gitignore vendored
View File

@ -164,3 +164,15 @@ Sicherungskopie_*
/screenshots/datastore_statistics_dataonly_small.png
/screenshots/datastore_statistics_hist_small.png
/screenshots/datastore_statistics_kde_small.png
/doc/images/JKQTPGLSimpleBoxAndLineVertical_small.png
/doc/images/JKQTPGLSimpleBoxAndLine_small.png
/doc/images/JKQTPGLSimpleVertical_small.png
/doc/images/JKQTPGLSimple_small.png
/doc/images/JKQTPGLabelAboveData_small.png
/doc/images/JKQTPGLabelAwayFromXAxis_small.png
/doc/images/JKQTPGLabelAwayFromYAxis_small.png
/doc/images/JKQTPGLabelBelowData_small.png
/doc/images/JKQTPGLabelLeftHandSide_small.png
/doc/images/JKQTPGLabelRightHandSide_small.png
/doc/images/JKQTPGLabelTowardsXAxis_small.png
/doc/images/JKQTPGLabelTowardsYAxis_small.png

View File

@ -244,6 +244,7 @@ if(JKQtPlotter_BUILD_EXAMPLES)
datastore_statistics_2d/datastore_statistics_2d
multithreaded/multithreaded/--mdfile=${CMAKE_CURRENT_LIST_DIR}/../examples/multithreaded/README.md
#"multithreaded_complex[multithreaded]/multithreaded_complex/--mdfile=${CMAKE_CURRENT_LIST_DIR}/../examples/multithreaded/README.md --complexlabel"
graphlabels/graphlabels,graphlabels_hor
)
@ -271,6 +272,7 @@ if(JKQtPlotter_BUILD_EXAMPLES)
symbols_and_errors/JKQTPXYLineErrorGraph_JKQTPErrorBars,JKQTPXYLineErrorGraph_JKQTPErrorLines,JKQTPXYLineErrorGraph_JKQTPErrorPolygons/--iteratefunctorsteps--iteratefunctorsteps_suppressinitial--smallscreenshotplot
boxplot/JKQTPBoxplotVerticalGraph,JKQTPBoxplotHorizontalGraph/--iteratefunctorsteps--iteratefunctorsteps_suppressinitial--smallscreenshotplot
second_axis/JKQTBasePlotter_addSecondaryYAxis,JKQTBasePlotter_addSecondaryXAxis
graphlabels/JKQTPGLabelAwayFromXAxis,JKQTPGLabelAwayFromYAxis,JKQTPGLabelTowardsXAxis,JKQTPGLabelTowardsYAxis,JKQTPGLabelAboveData,JKQTPGLabelRightHandSide,JKQTPGLabelBelowData,JKQTPGLabelLeftHandSide,JKQTPGLSimple,JKQTPGLSimpleVertical,JKQTPGLSimpleBoxAndLine,JKQTPGLSimpleBoxAndLineVertical,JKQTPGLSimpleBoxAndLineONLYLABELS,JKQTPGLSimpleBoxAndLineONLYLABELSVertical/--iteratefunctorsteps--smallscreenshotplot
)

View File

@ -113,6 +113,9 @@ All test-projects are Qt-projects that use qmake to build. You can load them int
<tr><td> \image html geo_coordinateaxis0_small.png
<td> \subpage JKQTPlotterGeometricCoordinateAxis0
<td> `JKQTPCoordinateAxisStyle::drawMode0`, `JKQTPGeoPolygon`, `JKQTPGeoEllipse`
<tr><td> \image html JKQTPGLSimpleBoxAndLineONLYLABELS_small.png
<td> \subpage JKQTPXYGraphLabels
<td> `JKQTPXYGraphLabels`
</table>
\subsection jkqtp_extut_keyaxesstyles Examples for Styling the Plot, Keys, Axes, ...

View File

@ -29,7 +29,10 @@ These classes are used by JKQTPlotterBase to output the plot.
\defgroup jkqtplotter_basegraphserrors Mix-In Classes for Error Indicators
\ingroup jkqtplotter_mixins
\defgroup jkqtplotter_basegraphs_stylemixins Mix-In Classes for Plot Styling
\defgroup jkqtplotter_basegraphs_stylemixins Mix-In Classes for Styling General Graphs
\ingroup jkqtplotter_mixins
\defgroup jkqtplotter_specialgraphs_stylemixins Mix-In Classes for Styling Specialized Graphs (Boxplots etz.)
\ingroup jkqtplotter_mixins
@ -116,6 +119,21 @@ This group assembles graphs that show their data with symbols and optionally wit
</table>
\defgroup jkqtplotter_graphlabels Labeling Datapoints
\ingroup jkqtplotter_concretegraphs
This group assembles graphs that add (textual) labels to the datapoints in a plot:
<table>
<tr>
<th> Screenshot
<th> Classes
<tr>
<td>\image html JKQTPGLSimpleBoxAndLineONLYLABELS_small.png
<td> JKQTPXYGraphLabels
</table>
\defgroup jkqtplotter_filledgraphs Filled Polygon/Area Graphs
\ingroup jkqtplotter_concretegraphs
@ -243,6 +261,9 @@ Examples:
<tr>
<td>\image html geo_text_small.png
<td> JKQTPGeoText
<tr>
<td>\image html JKQTPGLSimpleBoxAndLineONLYLABELS_small.png
<td> JKQTPXYGraphLabels
<tr>
<td>\image html JKQTPHorizontalRange_small.png
<td> JKQTPHorizontalRange, JKQTPVerticalRange

View File

@ -20,7 +20,6 @@ This page lists several todos and wishes for future version of JKQTPlotter
<li>graphs: gant-chart as simplified vector field with (x,y1,y2) or (x1,x2,y), or (x,y,dx), (x,y,dy) ... different head/tail style</li>
<li>graphs: matrix plots with boxes, labels, ...</li>
<li>graphs: matrix plots with symbols: symbol-type, color, size should be parametric, cf. scatter plots</li>
<li>graphs: text labels at positions/for graphs</li>
<li>graphs: vector field graph (arrows), variant (x,y,dx,dy), (x,y,alpha,length), (x1,y1,x2,y2) ... different head/tail styles</li>
<li>graphs: waterfall charts (see https://en.wikipedia.org/wiki/Waterfall_chart)</li>
<li>graphs: parametrized variant of JKQTPSingleColumnSymbolsGraph (beeswarm plots etz.) where each symbol may have a color given by a second column</li>

View File

@ -127,6 +127,7 @@ Changes, compared to \ref page_whatsnew_V4_0_0 "v4.0.0" include:
<li>NEW/REWORKED all functions in JKQTBasePlotter are re-entrant, i.e. different instances can be used from different threads in parallel (although there is some overhead due to shared caches between the threads!). This is demonstrated and discussed in \ref JKQTPlotterMultiThreaded . </li>
<li>NEW: allow linear-gradient(), currentcolor, ... in brush definitions of style.ini-file ... and using it is cyberpunk and dark styles</li>
<li>NEW: style simple_noaxes.ini</li>
<li>NEW: JKQTPXYGraphLabels which can draw a label next to each datapoint in the given x/y-dataset. The labels can be x-/y- or x&y-coordinates or custom, then defined by a user-supplied functor (+example \ref JKQTPlotterGraphLabels)</li>
</ul></li>
<li>JKQTMathText:<ul>

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,310 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="103.33672mm"
height="28.842316mm"
id="svg3219"
sodipodi:version="0.32"
inkscape:version="1.1.2 (b8e25be833, 2022-02-05)"
sodipodi:docname="jkqtpxygraphlabels.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
inkscape:export-filename="C:\Jan\Programmieren\JKQtPlotter\doc\images\jkqtpxygraphlabels.png"
inkscape:export-xdpi="61.449596"
inkscape:export-ydpi="61.449596"
version="1.1"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs3221">
<marker
style="overflow:visible"
id="Arrow1Send"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Send"
inkscape:isstock="true">
<path
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path5531" />
</marker>
<marker
style="overflow:visible"
id="marker5794"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Sstart"
inkscape:isstock="true">
<path
transform="matrix(0.3,0,0,0.3,-0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:0.625;stroke-linejoin:round"
id="path5792" />
</marker>
<marker
style="overflow:visible"
id="Arrow2Sstart"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Sstart"
inkscape:isstock="true">
<path
transform="matrix(0.3,0,0,0.3,-0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:0.625;stroke-linejoin:round"
id="path5546" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Mend"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Mend"
inkscape:isstock="true">
<path
transform="matrix(-0.4,0,0,-0.4,-4,0)"
style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path5525" />
</marker>
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Lend"
style="overflow:visible">
<path
id="path3942"
style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
</marker>
<marker
inkscape:stockid="Arrow2Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Lstart"
style="overflow:visible">
<path
id="path3939"
style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(1.1,0,0,1.1,1.1,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lstart"
style="overflow:visible">
<path
id="path3921"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
transform="matrix(0.8,0,0,0.8,10,0)" />
</marker>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : -452.24953 : 1"
inkscape:vp_y="0 : 1066.6667 : 0"
inkscape:vp_z="793.70078 : -452.24953 : 1"
inkscape:persp3d-origin="396.85039 : -639.33614 : 1"
id="perspective3227" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.2314489"
inkscape:cx="252.54803"
inkscape:cy="-73.084639"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="2240"
inkscape:window-height="1329"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:pagecheckerboard="0"
inkscape:window-maximized="1" />
<metadata
id="metadata3224">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-21.442405,-12.040758)">
<g
id="g5366"
style="fill:#cccccc"
transform="matrix(1.4976605,0,0,1.4976605,-324.58377,-31.251985)"
inkscape:export-filename="C:\Jan\Programmieren\JKQtPlotter\doc\images\jkqtpxygraphlabels.png"
inkscape:export-xdpi="61.449596"
inkscape:export-ydpi="61.449596">
<rect
style="fill:#cccccc;stroke:#000000;stroke-width:1.00353;stroke-linejoin:round;stroke-miterlimit:10"
id="rect3209"
width="61.61441"
height="27.73167"
x="298.22592"
y="42.927017" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:22.4671px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.561677"
x="303.16748"
y="65.748497"
id="text4093"><tspan
sodipodi:role="line"
id="tspan4091"
x="303.16748"
y="65.748497"
style="fill:#000000;stroke-width:0.561677">label</tspan></text>
</g>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:16.6981px;line-height:0%;font-family:'Bitstream Vera Sans';text-align:center;text-anchor:middle;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1.39151px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="138.41815"
y="116.77113"
id="text6295"
transform="scale(1.0899925,0.91743751)"
inkscape:export-filename="C:\Jan\Programmieren\JKQtPlotter\doc\images\jkqtpxygraphlabels.png"
inkscape:export-xdpi="61.449596"
inkscape:export-ydpi="61.449596"><tspan
sodipodi:role="line"
id="tspan6297"
x="138.41815"
y="116.77113"
style="font-size:30.0009px;line-height:1.25;fill:#0000ff;stroke:none;stroke-width:1.39151px">+</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:23.4608px;line-height:0%;font-family:'Bitstream Vera Sans';text-align:center;text-anchor:middle;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1.95506px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="176.46564"
y="115.88972"
id="text6299"
inkscape:export-filename="C:\Jan\Programmieren\JKQtPlotter\doc\images\jkqtpxygraphlabels.png"
inkscape:export-xdpi="61.449596"
inkscape:export-ydpi="61.449596"><tspan
sodipodi:role="line"
x="176.46564"
y="115.88972"
style="font-size:21.5057px;line-height:1.25;fill:#0000ff;stroke-width:1.95506px"
id="tspan6303">(x, y)</tspan></text>
<path
style="fill:none;stroke:#ff0000;stroke-width:1.46956px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow2Sstart);marker-end:url(#Arrow1Send)"
d="M 145.35723,95.464988 V 77.489556"
id="path5401"
inkscape:export-filename="C:\Jan\Programmieren\JKQtPlotter\doc\images\jkqtpxygraphlabels.png"
inkscape:export-xdpi="61.449596"
inkscape:export-ydpi="61.449596" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:21.9208px;line-height:1.25;font-family:sans-serif;fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.548019"
x="19.316088"
y="96.100845"
id="text6890"
inkscape:export-filename="C:\Jan\Programmieren\JKQtPlotter\doc\images\jkqtpxygraphlabels.png"
inkscape:export-xdpi="61.449596"
inkscape:export-ydpi="61.449596"><tspan
sodipodi:role="line"
id="tspan6888"
x="19.316088"
y="96.100845"
style="stroke-width:0.548019">LabelOffset</tspan></text>
<path
style="fill:none;stroke:#ff0000;stroke-width:0.645401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow2Sstart);marker-end:url(#Arrow1Send)"
d="M 161.49675,40.391734 V 35.019722"
id="path8100"
inkscape:export-filename="C:\Jan\Programmieren\JKQtPlotter\doc\images\jkqtpxygraphlabels.png"
inkscape:export-xdpi="61.449596"
inkscape:export-ydpi="61.449596" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:21.9208px;line-height:1.25;font-family:sans-serif;fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.548019"
x="98.085098"
y="28.700565"
id="text8104"
inkscape:export-filename="C:\Jan\Programmieren\JKQtPlotter\doc\images\jkqtpxygraphlabels.png"
inkscape:export-xdpi="61.449596"
inkscape:export-ydpi="61.449596"><tspan
sodipodi:role="line"
id="tspan8102"
x="98.085098"
y="28.700565"
style="stroke-width:0.548019">LabelYPadding</tspan></text>
<path
style="fill:none;stroke:#ff0000;stroke-width:0.99328px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow2Sstart);marker-end:url(#Arrow1Send)"
d="m 212.15832,51.099655 h -8.26759"
id="path11778"
inkscape:export-filename="C:\Jan\Programmieren\JKQtPlotter\doc\images\jkqtpxygraphlabels.png"
inkscape:export-xdpi="61.449596"
inkscape:export-ydpi="61.449596" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:21.9208px;line-height:1.25;font-family:sans-serif;fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.548019"
x="217.15215"
y="58.137436"
id="text11782"
inkscape:export-filename="C:\Jan\Programmieren\JKQtPlotter\doc\images\jkqtpxygraphlabels.png"
inkscape:export-xdpi="61.449596"
inkscape:export-ydpi="61.449596"><tspan
sodipodi:role="line"
id="tspan11780"
x="217.15215"
y="58.137436"
style="stroke-width:0.548019">LabelXPadding</tspan></text>
<path
style="fill:none;stroke:#ff0000;stroke-width:0.99328px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Send)"
d="m 203.23396,70.791905 h 8.26759"
id="path13399"
inkscape:export-filename="C:\Jan\Programmieren\JKQtPlotter\doc\images\jkqtpxygraphlabels.png"
inkscape:export-xdpi="61.449596"
inkscape:export-ydpi="61.449596" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.99328px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Send)"
d="m 224.74512,70.791905 h -8.26759"
id="path13401"
inkscape:export-filename="C:\Jan\Programmieren\JKQtPlotter\doc\images\jkqtpxygraphlabels.png"
inkscape:export-xdpi="61.449596"
inkscape:export-ydpi="61.449596" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:21.9208px;line-height:1.25;font-family:sans-serif;fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.548019"
x="226.49074"
y="81.483917"
id="text13419"
inkscape:export-filename="C:\Jan\Programmieren\JKQtPlotter\doc\images\jkqtpxygraphlabels.png"
inkscape:export-xdpi="61.449596"
inkscape:export-ydpi="61.449596"><tspan
sodipodi:role="line"
id="tspan13417"
x="226.49074"
y="81.483917"
style="stroke-width:0.548019">LabelBorderWidth</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -74,6 +74,7 @@ if (JKQtPlotter_BUILD_LIB_JKQTPLOTTER)
add_subdirectory(geo_simple)
add_subdirectory(geo_coordinateaxis0)
add_subdirectory(geometric)
add_subdirectory(graphlabels)
add_subdirectory(imageplot)
add_subdirectory(imageplot_cimg)
add_subdirectory(imageplot_modifier)

View File

@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.23)
set(EXAMPLE_NAME graphlabels)
set(EXENAME jkqtptest_${EXAMPLE_NAME})
message( STATUS ".. Building Example ${EXAMPLE_NAME}" )
add_executable(${EXENAME} WIN32 ${EXAMPLE_NAME}.cpp)
target_link_libraries(${EXENAME} JKQTPExampleToolsLib)
target_include_directories(${EXENAME} PRIVATE ../../lib)
target_link_libraries(${EXENAME} ${jkqtplotter_namespace}JKQTPlotter${jkqtplotter_LIBNAME_VERSION_PART})
# precomiled headers to speed up compilation
if (JKQtPlotter_BUILD_WITH_PRECOMPILED_HEADERS)
target_precompile_headers(${EXENAME} REUSE_FROM jkqtptest_simpletest)
endif (JKQtPlotter_BUILD_WITH_PRECOMPILED_HEADERS)
# Installation
install(TARGETS ${EXENAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
#Installation of Qt DLLs on Windows
jkqtplotter_deployqt(${EXENAME})

View File

@ -0,0 +1,16 @@
# Example (JKQTPlotter): Simple Graph Labels Example {#JKQTPlotterGraphLabels}
This project (see [`graphlabels`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/graphlabels) demonstrates the use of JKQTPXYGraphLabels to add labels to the datapoints of a graph.
The source code of the main application is (see [`graphlabels.cpp`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/graphlabels/graphlabels.cpp):
```.cpp
```
The result looks like this:
![graphlabels](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/graphlabels.png)
or this:
![graphlabels_hor](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/graphlabels_hor.png)

View File

@ -0,0 +1,144 @@
/** \example graphlabels.cpp
* Shows how to draw datapoint labels using JKQTPXYGraphLabels
*
* \ref JKQTPlotterGraphLabels
*/
#include "jkqtpexampleapplication.h"
#include <QApplication>
#include "jkqtplotter/jkqtplotter.h"
#include "jkqtplotter/graphs/jkqtpscatter.h"
#include "jkqtplotter/graphs/jkqtpbarchart.h"
#include "jkqtplotter/graphs/jkqtpgraphlabels.h"
#include "jkqtpexampleapplication.h"
#define Ndata 6
template <class TCHART>
std::pair<TCHART*, JKQTPXYGraphLabels*> doExample(JKQTPlotter& plot, const QString& title, JKQTPGraphLabelPosition labPos)
{
// 1. create a plotter window and get a pointer to the internal datastore (for convenience)
plot.getPlotter()->setUseAntiAliasingForGraphs(true); // nicer (but slower) plotting
plot.getPlotter()->setUseAntiAliasingForSystem(true); // nicer (but slower) plotting
plot.getPlotter()->setUseAntiAliasingForText(true); // nicer (but slower) text rendering
JKQTPDatastore* ds=plot.getDatastore();
// 2. make up some arbitrary data to be used for plotting
const size_t columnX=ds->addLinearColumn(Ndata, -1,1,"x");
const size_t columnY=ds->addCalculatedColumnFromColumn(columnX, [](double x) { return jkqtp_roundToDigits(-sin(x*3.0),2);}, "data");
// 3. create barchart and line-chart to display the data:
TCHART* graph1=new TCHART(&plot);
graph1->setBarPositionColumn(columnX);
graph1->setBarHeightColumn(columnY);
graph1->setTitle(QObject::tr("dataset: bars"));
graph1->setColor(QColorWithAlphaF(graph1->getFillColor(),0.25));
JKQTPXYLineGraph* graph2=new JKQTPXYLineGraph(&plot);
if (typeid(TCHART)==typeid(JKQTPBarVerticalGraph)) {
graph2->setXColumn(columnX);
graph2->setYColumn(columnY);
} else {
graph2->setXColumn(columnY);
graph2->setYColumn(columnX);
}
graph2->setTitle(QObject::tr("dataset: lines"));
graph2->setColor(QColorWithAlphaF(graph2->getLineColor(),0.5));
// 4.1. create barchart to display the data:
JKQTPXYGraphLabels* graphLabels=new JKQTPXYGraphLabels((typeid(TCHART)==typeid(JKQTPBarVerticalGraph)) ? JKQTPXYGraphLabels::YValueLabel : JKQTPXYGraphLabels::XValueLabel, &plot);
graphLabels->setXColumn(graph1->getXColumn());
graphLabels->setYColumn(graph1->getYColumn());
// 4.2. set position of labels and some styling options
graphLabels->setLabelPosition(labPos);
graphLabels->setTextFontSize(14);
// 5. add the graphs to the plot, so it is actually displayed
plot.addGraph(graph1);
plot.addGraph(graph2);
plot.addGraph(graphLabels);
// 6. scale the plot so the graph is contained
plot.setXY(-1.5,1.5,-1.5,1.5);
// 7.modify the plot style a bit
plot.getXAxis()->setDrawMode1(JKQTPCADMLine);
plot.getXAxis()->setDrawMode2(JKQTPCADMLine);
plot.getYAxis()->setDrawMode1(JKQTPCADMLine);
plot.getYAxis()->setDrawMode2(JKQTPCADMLine);
// show plotter and make it a decent size
plot.setWindowTitle(title);
plot.show();
plot.resize(400/plot.devicePixelRatioF(),250/plot.devicePixelRatioF());
return {graph1, graphLabels};
}
int main(int argc, char* argv[])
{
JKQTPAppSettingController highDPIController(argc,argv);
JKQTPExampleApplication app(argc, argv);
JKQTPlotter plotV;
auto gV=doExample<JKQTPBarVerticalGraph>(plotV, "1: JKQTPXYGraphLabels+JKQTPBarVerticalGraph", JKQTPGLabelAwayFromXAxis);
JKQTPlotter plotH;
auto gH=doExample<JKQTPBarHorizontalGraph>(plotH, "2: JKQTPXYGraphLabels+JKQTPBarHorizontalGraph", JKQTPGLabelAwayFromYAxis);
app.addExportStepFunctor([&](){
gV.second->setLabelPosition(JKQTPGLabelTowardsXAxis);
gH.second->setLabelPosition(JKQTPGLabelTowardsYAxis);
plotV.redrawPlot();
plotH.redrawPlot();
});
app.addExportStepFunctor([&](){
gV.second->setLabelPosition(JKQTPGLabelAboveData);
gH.second->setLabelPosition(JKQTPGLabelRightHandSide);
plotV.redrawPlot();
plotH.redrawPlot();
});
app.addExportStepFunctor([&](){
gV.second->setLabelPosition(JKQTPGLabelBelowData);
gH.second->setLabelPosition(JKQTPGLabelLeftHandSide);
plotV.redrawPlot();
plotH.redrawPlot();
});
app.addExportStepFunctor([&](){
gV.second->setLabelPosition(JKQTPGLabelAwayFromXAxis);
gV.second->setLabelBoxType(JKQTPGLSimpleBox);
gV.second->setDrawLabelBoxFrame(true);
gH.second->setLabelPosition(JKQTPGLabelAwayFromYAxis);
gH.second->setLabelBoxType(JKQTPGLSimpleBox);
gH.second->setDrawLabelBoxFrame(true);
plotV.redrawPlot();
plotH.redrawPlot();
});
app.addExportStepFunctor([&](){
gV.second->setLabelPosition(JKQTPGLabelAwayFromXAxis);
gV.second->setLabelBoxType(JKQTPGLSimpleBoxAndLine);
gV.second->setDrawLabelBoxFrame(true);
gH.second->setLabelPosition(JKQTPGLabelAwayFromYAxis);
gH.second->setLabelBoxType(JKQTPGLSimpleBoxAndLine);
gH.second->setDrawLabelBoxFrame(true);
plotV.redrawPlot();
plotH.redrawPlot();
});
app.addExportStepFunctor([&](){
//plotV.getPlotter()->setOnlyGraphVisible(plotV.getPlotter()->indexOfGraph(gV.second));
//plotH.getPlotter()->setOnlyGraphVisible(plotH.getPlotter()->indexOfGraph(gH.second));
gV.first->setVisible(false);
gH.first->setVisible(false);
plotV.redrawPlot();
plotH.redrawPlot();
});
return app.exec();
}

View File

@ -97,10 +97,10 @@ This test results in the following numbers (on my AMD Ryzen5 8/16-core laptop):
<b>VERSION:</b> 5.0.0
<b>BUILD MODE:</b> Release
<u><b>SERIAL RESULTS:</b></u><br/>runtime, overall = 11199.2ms<br/>single runtimes = (466.6 +/- 1681.5) ms<br/>speedup = 1.00x<br/>threads / available = 1 / 16<br/><br/><br/>
<u><b>SERIAL RESULTS:</b></u><br/>runtime, overall = 12353.5ms<br/>single runtimes = (514.6 +/- 1737.1) ms<br/>speedup = 1.00x<br/>threads / available = 1 / 16<br/><br/><br/>
<u><b>PARALLEL RESULTS:</b></u><br/>
runtime, overall = 2157.8ms<br/>single runtimes = (596.8 +/- 85.1) ms<br/>speedup = 6.64x<br/>threads / available = 8 / 16<br/>batch runs = 3<br/><br/><b>speedup vs. serial = 5.2x</b>
runtime, overall = 3440.1ms<br/>single runtimes = (739.1 +/- 91.8) ms<br/>speedup = 5.16x<br/>threads / available = 8 / 16<br/>batch runs = 3<br/><br/><b>speedup vs. serial = 3.6x</b>
[comment]:RESULTS_END

View File

@ -57,6 +57,7 @@ isEmpty(JKQTP_PLOTTER_PRI_INCLUDED) {
$$PWD/jkqtplotter/graphs/jkqtpbarchart.h \
$$PWD/jkqtplotter/graphs/jkqtpevaluatedparametriccurve.h \
$$PWD/jkqtplotter/graphs/jkqtplines.h \
$$PWD/jkqtplotter/graphs/jkqtpgraphlabels.h \
$$PWD/jkqtplotter/gui/jkqtpcomboboxes.h \
$$PWD/jkqtplotter/gui/jkqtpenhancedspinboxes.h \
$$PWD/jkqtplotter/gui/jkqtpenhancedtableview.h \
@ -111,6 +112,7 @@ isEmpty(JKQTP_PLOTTER_PRI_INCLUDED) {
$$PWD/jkqtplotter/graphs/jkqtpbarchart.cpp \
$$PWD/jkqtplotter/graphs/jkqtpevaluatedparametriccurve.cpp \
$$PWD/jkqtplotter/graphs/jkqtplines.cpp \
$$PWD/jkqtplotter/graphs/jkqtpgraphlabels.cpp \
$$PWD/jkqtplotter/gui/jkqtpcomboboxes.cpp \
$$PWD/jkqtplotter/gui/jkqtpenhancedspinboxes.cpp \
$$PWD/jkqtplotter/gui/jkqtpenhancedtableview.cpp \

View File

@ -31,6 +31,8 @@ target_sources(${lib_name} PRIVATE
jkqtpstatisticsadaptors.cpp
jkqtpevaluatedparametriccurve.cpp
jkqtplines.cpp
jkqtpgraphlabelstylemixin.cpp
jkqtpgraphlabels.cpp
)
# ... and add headers
target_sources(${lib_name} PUBLIC FILE_SET HEADERS TYPE HEADERS
@ -64,4 +66,6 @@ target_sources(${lib_name} PUBLIC FILE_SET HEADERS TYPE HEADERS
jkqtpbarchart.h
jkqtpevaluatedparametriccurve.h
jkqtplines.h
jkqtpgraphlabelstylemixin.h
jkqtpgraphlabels.h
)

View File

@ -34,7 +34,7 @@
/*! \brief Styling Mix-In for Boxplots
\ingroup jkqtplotter_basegraphs_stylemixins
\ingroup jkqtplotter_specialgraphs_stylemixins
\image html plot_boxplothorizontalelement.png

View File

@ -0,0 +1,216 @@
/*
Copyright (c) 2008-2022 Jan W. Krieger (<jan@jkrieger.de>)
This software is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License (LGPL) as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License (LGPL) for more details.
You should have received a copy of the GNU Lesser General Public License (LGPL)
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "jkqtplotter/graphs/jkqtpgraphlabels.h"
#include "jkqtplotter/jkqtpbaseplotter.h"
#include "jkqtplotter/jkqtplotter.h"
#include <QDebug>
#include <QDateTime>
#include "jkqtcommon/jkqtpdrawingtools.h"
#include "jkqtplotter/jkqtptools.h"
#define SmallestGreaterZeroCompare_xvsgz() if ((xvsgz>10.0*DBL_MIN)&&((smallestGreaterZero<10.0*DBL_MIN) || (xvsgz<smallestGreaterZero))) smallestGreaterZero=xvsgz;
JKQTPXYGraphLabels::JKQTPXYGraphLabels(LabelContentsDefaultType lt, JKQTPlotter* parent):
JKQTPXYGraphLabels(lt, parent->getPlotter())
{
}
JKQTPXYGraphLabels::JKQTPXYGraphLabels(const LabelGenerator &lgen, JKQTBasePlotter *parent):
JKQTPXYGraphLabels(YValueLabel, parent)
{
setCustomLabelGenerator(lgen);
}
JKQTPXYGraphLabels::JKQTPXYGraphLabels(const LabelGenerator &lgen, JKQTPlotter *parent):
JKQTPXYGraphLabels(lgen, parent->getPlotter())
{
}
JKQTPXYGraphLabels::JKQTPXYGraphLabels(LabelContentsDefaultType lt, JKQTBasePlotter* parent):
JKQTPXYGraph(parent), JKQTPGraphValueLabelStyleMixin(parent)
{
sortData=JKQTPXYGraph::Unsorted;
initValueLabelStyle(parent, parentPlotStyle, JKQTPPlotStyleType::Default);
switch(lt) {
case XValueLabel:
setDefaultXLabelGenerator();
break;
case YValueLabel:
setDefaultYLabelGenerator();
break;
case XYValueLabel:
setDefaultXYLabelGenerator();
break;
}
}
void JKQTPXYGraphLabels::draw(JKQTPEnhancedPainter& painter) {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaaot("JKQTPXYGraphLabels::draw");
#endif
if (parent==nullptr) return;
const JKQTPDatastore* datastore=parent->getDatastore();
if (datastore==nullptr) return;
drawErrorsBefore(painter);
{
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
int imax=0;
int imin=0;
if (getIndexRange(imin, imax)) {
for (int iii=imin; iii<imax; iii++) {
const int i=qBound(imin, getDataIndex(iii), imax);
const double xv=datastore->get(static_cast<size_t>(xColumn),static_cast<size_t>(i));
const double yv=datastore->get(static_cast<size_t>(yColumn),static_cast<size_t>(i));
const double x=transformX(xv);
const double y=transformY(yv);
if (JKQTPIsOKFloat(xv) && JKQTPIsOKFloat(yv) && JKQTPIsOKFloat(x) && JKQTPIsOKFloat(y)) {
const QString label=generateLabel(xv,yv,iii);
drawLabel(painter, QPointF(x,y), QPointF(xv,yv), label, parent);
}
}
}
}
drawErrorsAfter(painter);
}
void JKQTPXYGraphLabels::drawKeyMarker(JKQTPEnhancedPainter& painter, const QRectF& rect) {
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
painter.setFont(QFont(QGuiApplication::font().family(), getTextFontSize()));
painter.setPen(getTextColor());
painter.drawText(rect,Qt::AlignHCenter|Qt::AlignVCenter, "12");
}
QColor JKQTPXYGraphLabels::getKeyLabelColor() const {
return getTextColor();
}
void JKQTPXYGraphLabels::setColor(QColor c, bool setTextColor_, bool setFrameColor_)
{
if (setTextColor_) setTextColor(c);
if (setFrameColor_) setLineColor(c);
}
void JKQTPXYGraphLabels::setCustomLabelGenerator(const LabelGenerator &labgen)
{
m_labelGenerator=labgen;
}
void JKQTPXYGraphLabels::setDefaultXLabelGenerator()
{
m_labelGenerator=std::bind(std::mem_fn(&JKQTPXYGraphLabels::generateDefaultXLabel), this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
}
void JKQTPXYGraphLabels::setDefaultYLabelGenerator()
{
m_labelGenerator=std::bind(std::mem_fn(&JKQTPXYGraphLabels::generateDefaultYLabel), this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
}
void JKQTPXYGraphLabels::setDefaultXYLabelGenerator()
{
m_labelGenerator=std::bind(std::mem_fn(&JKQTPXYGraphLabels::generateDefaultXYLabel), this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
}
bool JKQTPXYGraphLabels::getXMinMax(double &minx, double &maxx, double &smallestGreaterZero)
{
const bool baseResult=JKQTPXYGraph::getXMinMax(minx,maxx,smallestGreaterZero);
if (baseResult) {
/*
// this does not work, as it depends on the widget size, when called!!!
qDebug()<<"JKQTPXYGraphLabels::getXMinMax():";
qDebug()<<" minx="<<minx<<", maxx="<<maxx;
const double delta=(isLabelPositioningGrowingInY())? 0.0: parent->pt2px(getLabelOffset()+getLabelXPadding()+getTextFontSize()*2.0,96.0);
const double mi_x=transformX(minx);
const double ma_x=transformX(maxx);
qDebug()<<" mi_x="<<mi_x<<", ma_x="<<ma_x<<", delta="<<delta;
const double new_mi_x=backtransformX(qMin(mi_x,ma_x)-delta);
const double new_ma_x=backtransformX(qMax(mi_x,ma_x)+delta);
qDebug()<<" new_mi_x="<<new_mi_x<<", new_ma_x="<<new_ma_x;
minx=qMin(minx,qMin(new_mi_x,new_ma_x));
maxx=qMax(maxx,qMax(new_mi_x,new_ma_x));
qDebug()<<"->minx="<<minx<<", maxx="<<maxx;*/
// ... so if required, we just extend the range by ~15%
if (!isLabelPositioningGrowingInX()) {
const double mi_x=transformY(minx);
const double ma_x=transformY(maxx);
const double delta=fabs(ma_x-mi_x)*0.15/2.0;
const double new_mi=backtransformY(qMax(mi_x,ma_x)+delta);
const double new_ma=backtransformY(qMin(mi_x,ma_x)-delta);
minx=qMin(minx,qMin(new_mi,new_ma));
maxx=qMax(maxx,qMax(new_mi,new_ma));
}
}
return baseResult;
}
bool JKQTPXYGraphLabels::getYMinMax(double &miny, double &maxy, double &smallestGreaterZero)
{
const bool baseResult=JKQTPXYGraph::getYMinMax(miny,maxy,smallestGreaterZero);
if (baseResult) {
/*
qDebug()<<"JKQTPXYGraphLabels::getXMinMax():";
qDebug()<<" minx="<<miny<<", maxx="<<maxy;
const double delta=(!isLabelPositioningGrowingInY())?0.0: parent->pt2px(getLabelOffset()+getLabelYPadding()*2.0+getTextFontSize(),96.0);
const double mi_y=transformY(miny);
const double ma_y=transformY(maxy);
qDebug()<<" mi_x="<<mi_y<<", ma_x="<<ma_y<<", delta="<<delta;
const double new_mi_y=backtransformY(qMin(mi_y,ma_y)-delta);
const double new_ma_y=backtransformY(qMax(mi_y,ma_y)+delta);
qDebug()<<" new_mi_x="<<new_mi_y<<", new_ma_x="<<new_ma_y;
miny=qMin(miny,qMin(new_mi_y,new_ma_y));
maxy=qMax(maxy,qMax(new_mi_y,new_ma_y));
qDebug()<<"->minx="<<miny<<", maxx="<<maxy;
*/
// ... so if required, we just extend the range by ~10%
if (isLabelPositioningGrowingInY()) {
const double mi_y=transformY(miny);
const double ma_y=transformY(maxy);
const double delta=fabs(ma_y-mi_y)*0.15/2.0;
const double new_mi=backtransformY(qMax(mi_y,ma_y)+delta);
const double new_ma=backtransformY(qMin(mi_y,ma_y)-delta);
miny=qMin(miny,qMin(new_mi,new_ma));
maxy=qMax(maxy,qMax(new_mi,new_ma));
}
}
return baseResult;
}
QString JKQTPXYGraphLabels::generateLabel(double x, double y, int index) const
{
if (m_labelGenerator) return m_labelGenerator(x,y,index);
else {
qWarning()<<"no label generator functor set in JKQTPXYGraphLabels";
return "";
}
}

View File

@ -0,0 +1,168 @@
/*
Copyright (c) 2008-2024 Jan W. Krieger (<jan@jkrieger.de>)
This software is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License (LGPL) as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License (LGPL) for more details.
You should have received a copy of the GNU Lesser General Public License (LGPL)
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef jkqtpgraphlabels_H
#define jkqtpgraphlabels_H
#include <QString>
#include <QPainter>
#include <QPair>
#include <functional>
#include "jkqtplotter/jkqtptools.h"
#include "jkqtplotter/jkqtplotter_imexport.h"
#include "jkqtplotter/jkqtpgraphsbase.h"
#include "jkqtplotter/graphs/jkqtpgraphlabelstylemixin.h"
// forward declarations
class JKQTBasePlotter;
class JKQTPlotter;
class JKQTPCoordinateAxis;
class JKQTPDatastore;
/*! \brief This graph plots a series of data labels. This can be used to add number-labels to e.g. a barchart.
\ingroup jkqtplotter_graphlabels
Sometimes it is necessary to display the numeric value of a datapoint right in the plot.
To achieve this, JKQTPXYGraphLabels is provided, which draws a text-label next to each datapoint in a
series of x- and y-values (thus it is derived from JKQTPXYGraph). Each label is drawn with a little offset
from the actual datapoint. Under each label, a small (stylable) box is drawn, which is by default simply
the same color as the background color of complete plot, but with transparency, thus providing a certain
level of contrast to the text, even if drawn above other plot elements. Use the properties of the parent
mix-in class JKQTPGraphValueLabelStyleMixin to style the text and the box.
Here is an example of labels together with a bars and lines chart:
\image html JKQTPGLabelAwayFromXAxis.png
To achieve this, use code like this:
\code
// create barchart and line-chart to display the data:
JKQTPBarVerticalGraph* graph1=new JKQTPBarVerticalGraph(&plot);
graph1->setBarPositionColumn(columnX);
graph1->setBarHeightColumn(columnY);
JKQTPXYLineGraph* graph2=new JKQTPXYLineGraph(&plot);
graph2->setXColumn(columnX);
graph2->setYColumn(columnY);
// create the data labels:
JKQTPXYGraphLabels* graphLabels=new JKQTPXYGraphLabels(JKQTPXYGraphLabels::YValueLabel, &plot);
graphLabels->setXColumn(graph1->getXColumn());
graphLabels->setYColumn(graph1->getYColumn());
graphLabels->setLabelPosition(JKQTPGLabelAwayFromXAxis),
// add the graphs to the plot, so it is actually displayed
plot.addGraph(graph1);
plot.addGraph(graph2);
plot.addGraph(graphLabels);
\endcode
The text shown in the label is determined by a functor of type JKQTPXYGraphLabels::LabelGenerator that calculates
it from the labels position and data-index.
This functor can be custimized (set setCustomLabelGenerator() or the matching constructor), or it may be one of
three default immplementations, that display:
- the current x-value (JKQTPXYGraphLabels::XValueLabel constructor arguent or setDefaultXLabelGenerator() )
- the current y-value (JKQTPXYGraphLabels::YValueLabel constructor arguent or setDefaultYLabelGenerator() )
- the current x- and y-value (JKQTPXYGraphLabels::XYValueLabel constructor arguent or setDefaultXYLabelGenerator() )
.
The default generators can be further customized with a series of properties on how to format their output:
- setXValueLabelFormat(), setYValueLabelFormat(), setXYValueLabelFormat() ... these set the basic label and are
typically only \c "$%1$" or \c "$%1/%2$" , but you can set them to any string (\c %1 / \c %2 is replaced by
the string-converted x-/y-values) and e.g. add a prefix, like \c setXValueLabelFormat("$x=%1$").
You can use any LaTeX-markup that is allowed by JKQTMathText here!
- setXDefaultConverter(), setXDefaultPrecision(), setXBelowIsZero(), ... (all these exist in X and Y variants!)
.
\see \ref JKQTPlotterGraphLabels
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPXYGraphLabels: public JKQTPXYGraph, public JKQTPGraphValueLabelStyleMixin, public JKQTPXYLabelsGeneratorMixin {
Q_OBJECT
public:
enum LabelContentsDefaultType {
XValueLabel, //!< \brief generates a label with the x-coordinate only, calls setDefaultXLabelGenerator()
YValueLabel, //!< \brief generates a label with the y-coordinate only, calls setDefaultYLabelGenerator()
XYValueLabel //!< \brief generates a label with the x- and y-coordinate, calls setDefaultXYLabelGenerator()
};
Q_ENUM(LabelContentsDefaultType)
/** \brief type of a functor that generates a label */
typedef std::function<QString(double,double,int)> LabelGenerator;
/** \brief class constructor, generates a JKQTPXYGraphLabels with one of the default label generator functors (x-value, y-value or x+y-values) */
explicit JKQTPXYGraphLabels(LabelContentsDefaultType lt, JKQTBasePlotter* parent=nullptr);
/** \brief class constructor, generates a JKQTPXYGraphLabels with one of the default label generator functors (x-value, y-value or x+y-values) */
JKQTPXYGraphLabels(LabelContentsDefaultType lt, JKQTPlotter* parent);
/** \brief class constructor, generates a JKQTPXYGraphLabels with a custom LabelGenerator functor */
JKQTPXYGraphLabels(const LabelGenerator& lgen, JKQTBasePlotter* parent=nullptr);
/** \brief class constructor, generates a JKQTPXYGraphLabels with a custom LabelGenerator functor */
JKQTPXYGraphLabels(const LabelGenerator& lgen, JKQTPlotter* parent);
/** \brief plots the graph to the plotter object specified as parent */
virtual void draw(JKQTPEnhancedPainter& painter) override;
/** \brief plots a key marker inside the specified rectangle \a rect */
virtual void drawKeyMarker(JKQTPEnhancedPainter& painter, const QRectF& rect) override;
/** \brief returns the color to be used for the key label */
virtual QColor getKeyLabelColor() const override;
/** \copydoc JKQTPPlotElement::getXMinMax() */
virtual bool getXMinMax(double& minx, double& maxx, double& smallestGreaterZero) override;
/** \copydoc JKQTPPlotElement::getYMinMax() */
virtual bool getYMinMax(double& miny, double& maxy, double& smallestGreaterZero) override;
/** \brief set color of line and symbol */
void setColor(QColor c, bool setTextColor_=true, bool setFrameColor_=true);
/** \brief sets a custom label geneator function of type LabelGenerator to use
*
* \see m_labelGenerator, setDefaultXLabelGenerator(), setDefaultYLabelGenerator(), setDefaultXYLabelGenerator()
*/
void setCustomLabelGenerator(const LabelGenerator& labgen);
/** \brief sets the label geneator function to a default implementation, that prints the x-value only
*
* The generator uses m_xValueLabelFormat, m_xDefaultConverter, ...
* \see m_labelGenerator, setCustomLabelGenerator(), setDefaultXLabelGenerator(), setDefaultYLabelGenerator(), setDefaultXYLabelGenerator()
*/
void setDefaultXLabelGenerator();
/** \brief sets the label geneator function to a default implementation, that prints the y-value only
*
* The generator uses m_yValueLabelFormat, m_yDefaultConverter, ...
* \see m_labelGenerator, setCustomLabelGenerator(), setDefaultXLabelGenerator(), setDefaultYLabelGenerator(), setDefaultXYLabelGenerator()
*/
void setDefaultYLabelGenerator();
/** \brief sets the label geneator function to a default implementation, that prints the x- and y-value
*
* The generator uses m_xyValueLabelFormat, m_xDefaultConverter, m_yDefaultConverter, ...
* \see m_labelGenerator, setCustomLabelGenerator(), setDefaultXLabelGenerator(), setDefaultYLabelGenerator(), setDefaultXYLabelGenerator()
*/
void setDefaultXYLabelGenerator();
protected:
/** \brief generates the label at position (\a x , \a y ) and at the given data \a index */
QString generateLabel(double x, double y, int index) const;
private:
/** \brief generate the label for the datapoint at location (\a x , \a y ) and being the \a index -th value in the columns */
LabelGenerator m_labelGenerator;
};
#endif // jkqtpgraphlabels_H

View File

@ -0,0 +1,524 @@
/*
Copyright (c) 2008-2024 Jan W. Krieger (<jan@jkrieger.de>)
This software is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License (LGPL) as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License (LGPL) for more details.
You should have received a copy of the GNU Lesser General Public License (LGPL)
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "jkqtplotter/graphs/jkqtpgraphlabelstylemixin.h"
#include "jkqtplotter/jkqtpbaseplotter.h"
#include <QApplication>
#include <QDebug>
#include <QDateTime>
QString JKQTPGraphLabelPosition2String(JKQTPGraphLabelPosition pos)
{
switch(pos) {
case JKQTPGLabelAboveData: return "label_above_data";
case JKQTPGLabelBelowData: return "label_below_data";
case JKQTPGLabelLeftHandSide: return "label_left_hand_side";
case JKQTPGLabelRightHandSide: return "label_right_hand_side";
case JKQTPGLabelAwayFromXAxis: return "label_away_from_xaxis";
case JKQTPGLabelAwayFromYAxis: return "label_away_from_yaxis";
case JKQTPGLabelTowardsXAxis: return "label_towards_xaxis";
case JKQTPGLabelTowardsYAxis: return "label_towards_xaxis";
}
return "label_away_from_xaxis";
}
JKQTPGraphLabelPosition String2JKQTPGraphLabelPosition(const QString &pos)
{
const QString m=pos.trimmed().toLower();
if (m=="label_above_data" || m=="above_data" || m=="above") return JKQTPGLabelAboveData;
if (m=="label_below_data" || m=="below_data" || m=="below") return JKQTPGLabelBelowData;
if (m=="label_left_hand_side" || m=="left_hand_side" || m=="left_hand" || m=="left" || m=="lhs") return JKQTPGLabelLeftHandSide;
if (m=="label_right_hand_side" || m=="right_hand_side" || m=="right_hand" || m=="right" || m=="rhs") return JKQTPGLabelRightHandSide;
if (m=="label_away_from_xaxis" || m=="away_from_xaxis") return JKQTPGLabelAwayFromXAxis;
if (m=="label_away_from_yaxis" || m=="away_from_yaxis") return JKQTPGLabelAwayFromYAxis;
if (m=="label_towars_xaxis" || m=="towars_xaxis") return JKQTPGLabelTowardsXAxis;
if (m=="label_towars_yaxis" || m=="towars_yaxis") return JKQTPGLabelTowardsYAxis;
return JKQTPGraphLabelDefault;
}
QString JKQTPGraphLabelBoxType2String(JKQTPGraphLabelBoxType pos)
{
switch(pos) {
case JKQTPGLSimpleBox: return "simple_box";
case JKQTPGLSimpleBoxAndLine: return "simple_box_and_line";
}
return "simple_box";
}
JKQTPGraphLabelBoxType String2JKQTPGraphLabelBoxType(const QString &pos)
{
const QString m=pos.trimmed().toLower();
if (m=="simple_box" || m=="simple" || m=="box") return JKQTPGLSimpleBox;
if (m=="simple_box_and_line" || m=="box_and_line") return JKQTPGLSimpleBoxAndLine;
return JKQTPGraphLabelBoxDefault;
}
JKQTPGraphValueLabelStyleMixin::JKQTPGraphValueLabelStyleMixin(JKQTBasePlotter *parent):
JKQTPGraphTextStyleMixin(parent), JKQTPGraphLineStyleMixin(), JKQTPGraphFillStyleMixin()
{
m_labelOffset=getTextFontSize()/4.0;
m_labelOffsetWithConnector=getTextFontSize()*0.75;
m_labelBoxRounding=getTextFontSize()/3.0;
m_labelXPadding=getTextFontSize()/3.0;
m_labelYPadding=getTextFontSize()/8.0;
m_labelPosition=JKQTPGraphLabelDefault;
m_labelBoxType=JKQTPGLSimpleBox;
m_drawLabelBoxFrame=false;
setFillStyle(Qt::NoBrush);
}
void JKQTPGraphValueLabelStyleMixin::initValueLabelStyle(JKQTBasePlotter *parent, int &parentPlotStyle, JKQTPPlotStyleType styletype)
{
setFillStyle(Qt::NoBrush);
if (parent) { // get style settings from parent object
initTextStyle(parent, parentPlotStyle,styletype);
initLineStyle(parent, parentPlotStyle, styletype);
initFillStyle(parent, parentPlotStyle, styletype);
setFillColor(QColorWithAlphaF(parent->getCurrentPlotterStyle().plotBackgroundBrush.color(), 0.5));
setFillStyle(Qt::SolidPattern);
setLineWidth(parent->getCurrentPlotterStyle().keyStyle.frameWidth);
}
}
JKQTPGraphValueLabelStyleMixin::~JKQTPGraphValueLabelStyleMixin()
{
}
void JKQTPGraphValueLabelStyleMixin::setLabelOffset(double r)
{
m_labelOffset=r;
}
double JKQTPGraphValueLabelStyleMixin::getLabelOffset() const
{
return m_labelOffset;
}
double JKQTPGraphValueLabelStyleMixin::getUsedLabelOffset() const
{
if (m_labelBoxType==JKQTPGLSimpleBox) {
return m_labelOffset;
}
return m_labelOffsetWithConnector;
}
void JKQTPGraphValueLabelStyleMixin::setLabelOffsetWithConnector(double r)
{
m_labelOffsetWithConnector=r;
}
double JKQTPGraphValueLabelStyleMixin::getLabelOffsetWithConnector() const
{
return m_labelOffsetWithConnector;
}
void JKQTPGraphValueLabelStyleMixin::setLabelBoxRounding(double r)
{
m_labelBoxRounding=r;
}
double JKQTPGraphValueLabelStyleMixin::getLabelBoxRounding() const
{
return m_labelBoxRounding;
}
void JKQTPGraphValueLabelStyleMixin::setLabelXPadding(double r)
{
m_labelXPadding=r;
}
double JKQTPGraphValueLabelStyleMixin::getLabelXPadding() const
{
return m_labelXPadding;
}
void JKQTPGraphValueLabelStyleMixin::setLabelYPadding(double r)
{
m_labelYPadding=r;
}
double JKQTPGraphValueLabelStyleMixin::getLabelYPadding() const
{
return m_labelYPadding;
}
void JKQTPGraphValueLabelStyleMixin::setLabelPosition(JKQTPGraphLabelPosition r)
{
m_labelPosition=r;
}
JKQTPGraphLabelPosition JKQTPGraphValueLabelStyleMixin::getLabelPosition() const
{
return m_labelPosition;
}
bool JKQTPGraphValueLabelStyleMixin::isLabelPositioningGrowingInX() const
{
switch (m_labelPosition) {
case JKQTPGLabelAwayFromYAxis:
case JKQTPGLabelLeftHandSide:
case JKQTPGLabelRightHandSide:
return true;
case JKQTPGLabelAboveData:
case JKQTPGLabelBelowData:
case JKQTPGLabelAwayFromXAxis:
case JKQTPGLabelTowardsXAxis:
case JKQTPGLabelTowardsYAxis:
return false;
}
return false;
}
bool JKQTPGraphValueLabelStyleMixin::isLabelPositioningGrowingInY() const
{
switch (m_labelPosition) {
case JKQTPGLabelAwayFromXAxis:
case JKQTPGLabelAboveData:
case JKQTPGLabelBelowData:
return true;
case JKQTPGLabelAwayFromYAxis:
case JKQTPGLabelTowardsXAxis:
case JKQTPGLabelTowardsYAxis:
case JKQTPGLabelLeftHandSide:
case JKQTPGLabelRightHandSide:
return false;
}
return false;
}
void JKQTPGraphValueLabelStyleMixin::setDrawLabelBoxFrame(bool r)
{
m_drawLabelBoxFrame=r;
}
bool JKQTPGraphValueLabelStyleMixin::drawsLabelBoxFrame() const
{
return m_drawLabelBoxFrame;
}
void JKQTPGraphValueLabelStyleMixin::setLabelBoxType(JKQTPGraphLabelBoxType r)
{
m_labelBoxType=r;
}
JKQTPGraphLabelBoxType JKQTPGraphValueLabelStyleMixin::getLabelBoxType() const
{
return m_labelBoxType;
}
void JKQTPGraphValueLabelStyleMixin::drawLabel(JKQTPEnhancedPainter &painter, const QPointF &xDataPixel, const QPointF &xData, const QString &contents, JKQTBasePlotter *parent) const
{
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
// calculate geometry
const LabelGeometry g=calcLabelGeometry(painter, xDataPixel, xData, contents, parent);
// draw Box
if (m_drawLabelBoxFrame) painter.setPen(getLinePenForRects(painter, parent));
else painter.setPen(Qt::NoPen);
painter.setBrush(getFillBrush(painter, parent));
if (m_labelBoxType==JKQTPGLSimpleBox || m_labelBoxType==JKQTPGLSimpleBoxAndLine) {
painter.drawRoundedRectOrRect(g.boxRect, m_labelBoxRounding);
}
if (m_labelBoxType==JKQTPGLSimpleBoxAndLine) {
//qDebug()<<"linestyle="<<getLineStyle()<<", color="<<getLineColor()<<", width="<<getLineWidth();
painter.setPen(getLinePen(painter, parent));
switch(g.boxpos) {
case LabelGeometry::BoxLeft:
painter.drawLine(xDataPixel, QPointF(qMax(g.boxRect.left(),g.boxRect.right()), xDataPixel.y()));
break;
case LabelGeometry::BoxRight:
painter.drawLine(xDataPixel, QPointF(qMin(g.boxRect.left(),g.boxRect.right()), xDataPixel.y()));
break;
case LabelGeometry::BoxTop:
painter.drawLine(xDataPixel, QPointF(xDataPixel.x(), qMax(g.boxRect.top(),g.boxRect.bottom())));
break;
case LabelGeometry::BoxBottom:
painter.drawLine(xDataPixel, QPointF(xDataPixel.x(), qMin(g.boxRect.top(),g.boxRect.bottom())));
break;
}
}
// draw text
parent->getMathText()->setFontSpecial(getTextFontName());
parent->getMathText()->setFontSize(getTextFontSize()*parent->getFontSizeMultiplier());
parent->getMathText()->setFontColor(getTextColor());
parent->getMathText()->parse(contents);
parent->getMathText()->draw(painter, Qt::AlignVCenter|Qt::AlignHCenter, g.textRect, parent->getCurrentPlotterStyle().debugShowTextBoxes);
}
JKQTPGraphValueLabelStyleMixin::LabelGeometry JKQTPGraphValueLabelStyleMixin::calcLabelGeometry(JKQTPEnhancedPainter &painter, const QPointF &xDataPixel, const QPointF &xData, const QString &contents, JKQTBasePlotter *parent) const
{
LabelGeometry res;
res.label=contents;
res.labelOffsetPx=parent->pt2px(getUsedLabelOffset(),painter);
res.padX=parent->pt2px(m_labelXPadding,painter);
res.padY=parent->pt2px(m_labelYPadding,painter);
res.lw=parent->pt2px(getLineWidth(),painter);
res.textSize=parent->getTextSizeDetail(getTextFontName(), getTextFontSize(), contents, painter);
if(m_labelPosition==JKQTPGLabelAboveData || (m_labelPosition==JKQTPGLabelAwayFromXAxis && xData.y()>=0) || (m_labelPosition==JKQTPGLabelTowardsXAxis && xData.y()<0)) {
// label above
res.textRect=QRectF(xDataPixel.x()-res.textSize.width/2.0, xDataPixel.y()-res.labelOffsetPx-res.padY-res.lw/2.0-res.textSize.overallHeight, res.textSize.width, res.textSize.overallHeight);
res.boxpos=LabelGeometry::BoxTop;
} else if (m_labelPosition==JKQTPGLabelBelowData || (m_labelPosition==JKQTPGLabelAwayFromXAxis && xData.y()<0) || (m_labelPosition==JKQTPGLabelTowardsXAxis && xData.y()>=0)) {
// label below
res.textRect=QRectF(xDataPixel.x()-res.textSize.width/2.0, xDataPixel.y()+res.labelOffsetPx+res.padY+res.lw/2.0, res.textSize.width, res.textSize.overallHeight);
res.boxpos=LabelGeometry::BoxBottom;
} else if(m_labelPosition==JKQTPGLabelLeftHandSide || (m_labelPosition==JKQTPGLabelAwayFromYAxis && xData.x()<0) || (m_labelPosition==JKQTPGLabelTowardsYAxis && xData.x()>=0)) {
// lhs
res.textRect=QRectF(xDataPixel.x()-res.labelOffsetPx-res.padX-res.lw/2.0-res.textSize.width, xDataPixel.y()-res.textSize.overallHeight/2.0, res.textSize.width, res.textSize.overallHeight);
res.boxpos=LabelGeometry::BoxLeft;
} else if (m_labelPosition==JKQTPGLabelRightHandSide || (m_labelPosition==JKQTPGLabelAwayFromYAxis && xData.x()>=0) || (m_labelPosition==JKQTPGLabelTowardsYAxis && xData.x()<0)) {
// rhs
res.textRect=QRectF(xDataPixel.x()+res.labelOffsetPx+res.padX+res.lw/2.0, xDataPixel.y()-res.textSize.overallHeight/2.0, res.textSize.width, res.textSize.overallHeight);
res.boxpos=LabelGeometry::BoxRight;
}
res.boxRect=QRectF(res.textRect.x()-res.padX-res.lw/2.0, res.textRect.y()-res.padY-res.lw/2.0, res.textRect.width()+res.padX*2.0+res.lw, res.textRect.height()+res.padY*2.0+res.lw);
return res;
}
JKQTPXYLabelsGeneratorMixin::JKQTPXYLabelsGeneratorMixin():
m_xValueLabelFormat("$%1$"),
m_yValueLabelFormat("$%1$"),
m_xyValueLabelFormat("$%1 / %2$"),
m_xDefaultConverter(JKQTPGLDefaultConverter),
m_yDefaultConverter(JKQTPGLDefaultConverter),
m_xDefaultPrecision(4),
m_yDefaultPrecision(4),
m_xBelowIsZero(std::numeric_limits<double>::min()*4),
m_yBelowIsZero(std::numeric_limits<double>::min()*4),
m_xMinNoExponent(1e-3),
m_yMinNoExponent(1e-3),
m_xMaxNoExponent(1e4),
m_yMaxNoExponent(1e4),
m_xDateTimeFormat(QLocale().dateTimeFormat(QLocale::NarrowFormat)),
m_yDateTimeFormat(QLocale().dateTimeFormat(QLocale::NarrowFormat))
{
}
JKQTPXYLabelsGeneratorMixin::~JKQTPXYLabelsGeneratorMixin()
{
}
int JKQTPXYLabelsGeneratorMixin::getXDefaultPrecision() const
{
return m_xDefaultPrecision;
}
void JKQTPXYLabelsGeneratorMixin::setXDefaultPrecision(int v)
{
m_xDefaultPrecision=v;
}
int JKQTPXYLabelsGeneratorMixin::getYDefaultPrecision() const
{
return m_yDefaultPrecision;
}
void JKQTPXYLabelsGeneratorMixin::setYDefaultPrecision(int v)
{
m_yDefaultPrecision=v;
}
JKQTPGraphLabelConverterType JKQTPXYLabelsGeneratorMixin::getXDefaultConverter() const
{
return m_xDefaultConverter;
}
void JKQTPXYLabelsGeneratorMixin::setXDefaultConverter(JKQTPGraphLabelConverterType v)
{
m_xDefaultConverter=v;
}
JKQTPGraphLabelConverterType JKQTPXYLabelsGeneratorMixin::getYDefaultConverter() const
{
return m_yDefaultConverter;
}
void JKQTPXYLabelsGeneratorMixin::setYDefaultConverter(JKQTPGraphLabelConverterType v)
{
m_yDefaultConverter=v;
}
QString JKQTPXYLabelsGeneratorMixin::getXValueLabelFormat() const
{
return m_xValueLabelFormat;
}
void JKQTPXYLabelsGeneratorMixin::setXValueLabelFormat(const QString &v)
{
m_xValueLabelFormat=v;
}
QString JKQTPXYLabelsGeneratorMixin::getYValueLabelFormat() const
{
return m_yValueLabelFormat;
}
void JKQTPXYLabelsGeneratorMixin::setYValueLabelFormat(const QString &v)
{
m_yValueLabelFormat=v;
}
QString JKQTPXYLabelsGeneratorMixin::getXYValueLabelFormat() const
{
return m_xyValueLabelFormat;
}
void JKQTPXYLabelsGeneratorMixin::setXYValueLabelFormat(const QString &v)
{
m_xyValueLabelFormat=v;
}
double JKQTPXYLabelsGeneratorMixin::getXBelowIsZero() const
{
return m_xBelowIsZero;
}
void JKQTPXYLabelsGeneratorMixin::setXBelowIsZero(double v)
{
m_xBelowIsZero=v;
}
double JKQTPXYLabelsGeneratorMixin::getYBelowIsZero() const
{
return m_yBelowIsZero;
}
void JKQTPXYLabelsGeneratorMixin::setYBelowIsZero(double v)
{
m_yBelowIsZero=v;
}
double JKQTPXYLabelsGeneratorMixin::getXMinNoExponent() const
{
return m_xMinNoExponent;
}
void JKQTPXYLabelsGeneratorMixin::setXMinNoExponent(double v)
{
m_xMinNoExponent=v;
}
double JKQTPXYLabelsGeneratorMixin::getYMinNoExponent() const
{
return m_yMinNoExponent;
}
void JKQTPXYLabelsGeneratorMixin::setYMinNoExponent(double v)
{
m_yMinNoExponent=v;
}
double JKQTPXYLabelsGeneratorMixin::getXMaxNoExponent() const
{
return m_xMaxNoExponent;
}
void JKQTPXYLabelsGeneratorMixin::setXMaxNoExponent(double v)
{
m_xMaxNoExponent=v;
}
double JKQTPXYLabelsGeneratorMixin::getYMaxNoExponent() const
{
return m_yMaxNoExponent;
}
void JKQTPXYLabelsGeneratorMixin::setYMaxNoExponent(double v)
{
m_yMaxNoExponent=v;
}
QString JKQTPXYLabelsGeneratorMixin::getXDateTimeFormmat() const
{
return m_xDateTimeFormat;
}
void JKQTPXYLabelsGeneratorMixin::setXDateTimeFormmat(const QString &v)
{
m_xDateTimeFormat=v;
}
QString JKQTPXYLabelsGeneratorMixin::getYDateTimeFormmat() const
{
return m_yDateTimeFormat;
}
void JKQTPXYLabelsGeneratorMixin::setYDateTimeFormmat(const QString &v)
{
m_yDateTimeFormat=v;
}
QString JKQTPXYLabelsGeneratorMixin::generateDefaultXLabel(double x, double , int ) const
{
return m_xValueLabelFormat.arg(xValToString(x));
}
QString JKQTPXYLabelsGeneratorMixin::generateDefaultYLabel(double , double y, int ) const
{
return m_yValueLabelFormat.arg(yValToString(y));
}
QString JKQTPXYLabelsGeneratorMixin::generateDefaultXYLabel(double x, double y, int ) const
{
return m_xyValueLabelFormat.arg(xValToString(x)).arg(yValToString(y));
}
QString JKQTPXYLabelsGeneratorMixin::valToString(double x, JKQTPGraphLabelConverterType converter, int precision, double belowIsZero, double minNoExponent, double maxNoExponent, const QString& dateTimeFormat)
{
switch(converter) {
case JKQTPGLCdecimal: return jkqtp_floattoqstr(x,'f',precision,true);
case JKQTPGLCscientific: return jkqtp_floattoqstr(x,'e',precision,true);
case JKQTPGLCexponentCharacter: return jkqtp_floattolatexunitqstr(x,precision,true, belowIsZero);
case JKQTPGLCexponent: return jkqtp_floattolatexqstr(x,precision,true, belowIsZero,minNoExponent,maxNoExponent);
case JKQTPGLCdatetime: {
QDateTime dt;
dt.setMSecsSinceEpoch(uint64_t(x));
return dt.toString(dateTimeFormat);
}
}
qWarning()<<"unknown m_xDefaultConverter="<<converter<<" in JKQTPXYLabelsGeneratorMixin::xValToString()";
return "";
}
QString JKQTPXYLabelsGeneratorMixin::xValToString(double x) const
{
return valToString(x, m_xDefaultConverter,m_xDefaultPrecision, m_xBelowIsZero, m_xMinNoExponent,m_xMaxNoExponent, m_xDateTimeFormat);
}
QString JKQTPXYLabelsGeneratorMixin::yValToString(double x) const
{
return valToString(x, m_yDefaultConverter,m_yDefaultPrecision, m_yBelowIsZero, m_yMinNoExponent,m_yMaxNoExponent, m_yDateTimeFormat);
}

View File

@ -0,0 +1,429 @@
/*
Copyright (c) 2008-2024 Jan W. Krieger (<jan@jkrieger.de>)
This software is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License (LGPL) as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License (LGPL) for more details.
You should have received a copy of the GNU Lesser General Public License (LGPL)
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef jkqtpgraphlabelstylemixin_H
#define jkqtpgraphlabelstylemixin_H
#include <QString>
#include <QPainter>
#include <QPen>
#include <QBrush>
#include "jkqtplotter/jkqtptools.h"
#include "jkqtplotter/jkqtplotter_imexport.h"
#include "jkqtplotter/jkqtpbaseplotter.h"
#include "jkqtcommon/jkqtpdrawingtools.h"
#include "jkqtplotter/jkqtplotter_configmacros.h"
#include "jkqtplotter/jkqtpgraphsbasestylingmixins.h"
class JKQTPlotter; // forward
/** \brief position of a label near a data-point, used by JKQTPGraphValueLabelStyleMixin
* \ingroup jkqtplotter_specialgraphs_stylemixins
*
* \see JKQTPGraphValueLabelStyleMixin
*/
enum JKQTPGraphLabelPosition {
JKQTPGLabelAboveData=0, /*!< \brief all labels always above the datapoint \image html JKQTPGLabelAboveData.png */
JKQTPGLabelBelowData, /*!< \brief all labels always below the datapoint \image html JKQTPGLabelBelowData.png */
JKQTPGLabelTowardsXAxis, /*!< \brief all labels between the datapoint and the x-axis the datapoint \image html JKQTPGLabelTowardsXAxis.png */
JKQTPGLabelAwayFromXAxis, /*!< \brief all labels pointing away from the x-axis \image html JKQTPGLabelAwayFromXAxis.png */
JKQTPGLabelRightHandSide, /*!< \brief all labels always on the right-hand side of the datapoint \image html JKQTPGLabelRightHandSide.png */
JKQTPGLabelLeftHandSide, /*!< \brief all labels always on the left-hand side of the datapoint \image html JKQTPGLabelLeftHandSide.png */
JKQTPGLabelTowardsYAxis, /*!< \brief all labels between the datapoint and the y-axis the datapoint \image html JKQTPGLabelTowardsYAxis.png */
JKQTPGLabelAwayFromYAxis, /*!< \brief all labels pointing away from the y-axis \image html JKQTPGLabelAwayFromYAxis.png */
JKQTPGraphLabelDefault=JKQTPGLabelAwayFromXAxis,
};
/** \brief converts a JKQTPGraphLabelPosition variable into a human-readable string
* \ingroup jkqtplotter_specialgraphs_stylemixins
*/
JKQTPLOTTER_LIB_EXPORT QString JKQTPGraphLabelPosition2String(JKQTPGraphLabelPosition pos);
/** \brief converts a String into a JKQTPGraphLabelPosition
* \ingroup jkqtplotter_specialgraphs_stylemixins
*/
JKQTPLOTTER_LIB_EXPORT JKQTPGraphLabelPosition String2JKQTPGraphLabelPosition(const QString& pos);
/** \brief type of box surrounding a label near a data-point, used by JKQTPGraphValueLabelStyleMixin
* \ingroup jkqtplotter_specialgraphs_stylemixins
*
* \see JKQTPGraphValueLabelStyleMixin
*/
enum JKQTPGraphLabelBoxType {
JKQTPGLSimpleBox=0, /*!< \brief a simple (possibly rounded and outlined) box \image html JKQTPGLSimpleBox.png */
JKQTPGLSimpleBoxAndLine=1, /*!< \brief a simple (possibly rounded and outlined) box, connected to the datapoint by a line \image html JKQTPGLSimpleBoxAndLine.png */
JKQTPGraphLabelBoxDefault=JKQTPGLSimpleBox,
};
/** \brief converts a JKQTPGraphLabelBoxType variable into a human-readable string
* \ingroup jkqtplotter_specialgraphs_stylemixins
*/
JKQTPLOTTER_LIB_EXPORT QString JKQTPGraphLabelBoxType2String(JKQTPGraphLabelBoxType pos);
/** \brief converts a String into a JKQTPGraphLabelBoxType
* \ingroup jkqtplotter_specialgraphs_stylemixins
*/
JKQTPLOTTER_LIB_EXPORT JKQTPGraphLabelBoxType String2JKQTPGraphLabelBoxType(const QString& pos);
/*! \brief This Mix-In class provides setter/getter methods, storage and other facilities for value labels in graphs
\ingroup jkqtplotter_specialgraphs_stylemixins
in addition to all properties of JKQTPGraphTextStyleMixin for the actual label text,
JKQTPGraphLineStyleMixin & JKQTPGraphFillStyleMixin for a box around the label,
it also supports properties for positioning and further sryling the labels.
supported properties:
- padding from actual label to border
- distance of label to actual datapoint
- positioning of the label
- styling for the box around the label
.
\image html jkqtpxygraphlabels.png
\see JKQTPGraphTextStyleMixin, JKQTPGraphLineStyleMixin, JKQTPGraphFillStyleMixin, JKQTPXYGraphLabels
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPGraphValueLabelStyleMixin: public JKQTPGraphTextStyleMixin, public JKQTPGraphLineStyleMixin, public JKQTPGraphFillStyleMixin {
#ifndef JKQTPLOTTER_WORKAROUND_QGADGET_BUG
Q_GADGET
#endif
public:
/** \brief class constructor */
JKQTPGraphValueLabelStyleMixin(JKQTBasePlotter *parent);
/** \brief initiaize the fill style (from the parent plotter) */
void initValueLabelStyle(JKQTBasePlotter* parent, int &parentPlotStyle, JKQTPPlotStyleType styletype=JKQTPPlotStyleType::Default);
virtual ~JKQTPGraphValueLabelStyleMixin();
/** \copydoc m_labelOffset */
void setLabelOffset(double r);
/** \copydoc m_labelOffset */
double getLabelOffset() const;
/** \brief determines, whether to use getLabelOffset() or getLabelOffsetWithConnector() (or something else) and returns it */
double getUsedLabelOffset() const;
/** \copydoc m_labelOffsetWithConnector */
void setLabelOffsetWithConnector(double r);
/** \copydoc m_labelOffsetWithConnector */
double getLabelOffsetWithConnector() const;
/** \copydoc m_labelBoxRounding */
void setLabelBoxRounding(double r);
/** \copydoc m_labelBoxRounding */
double getLabelBoxRounding() const;
/** \copydoc m_labelXPadding */
void setLabelXPadding(double r);
/** \copydoc m_labelXPadding */
double getLabelXPadding() const;
/** \copydoc m_labelYPadding */
void setLabelYPadding(double r);
/** \copydoc m_labelYPadding */
double getLabelYPadding() const;
/** \copydoc m_labelPosition */
void setLabelPosition(JKQTPGraphLabelPosition r);
/** \copydoc m_labelPosition */
JKQTPGraphLabelPosition getLabelPosition() const;
/** \brief determines whether a label is positioned left of the mininmum, or right of the maxinmum datapoint (\c true ) */
bool isLabelPositioningGrowingInX() const;
/** \brief determines whether a label is positioned below the mininmum, or above the maxinmum datapoint (\c true ) */
bool isLabelPositioningGrowingInY() const;
/** \copydoc m_drawLabelBoxFrame */
void setDrawLabelBoxFrame(bool r);
/** \copydoc m_drawLabelBoxFrame */
bool drawsLabelBoxFrame() const;
/** \copydoc m_labelBoxType */
void setLabelBoxType(JKQTPGraphLabelBoxType r);
/** \copydoc m_labelBoxType */
JKQTPGraphLabelBoxType getLabelBoxType() const;
/** \brief draws a label, including its box
*
* \brief painter the JKQTPEnhancedPainter to use for drawing
* \brief xDataPixel position of the labeled datapoint in (screen) pixels
* \brief xData x- and y-coordinate of the datapoint (needed for some JKQTPGraphLabelPosition)
* \brief contents the text to be rendered
* \brief parent the JKQTPBasePlotter in whos context we are drawing (e.g. needed to render \a contents )
*
*/
void drawLabel(JKQTPEnhancedPainter& painter, const QPointF& xDataPixel, const QPointF& xData, const QString& contents, JKQTBasePlotter *parent) const;
#ifndef JKQTPLOTTER_WORKAROUND_QGADGET_BUG
Q_PROPERTY(double labelOffset MEMBER m_labelOffset READ getLabelOffset WRITE setLabelOffset)
Q_PROPERTY(double labelOffsetWithConnector MEMBER m_labelOffsetWithConnector READ getLabelOffsetWithConnector WRITE setLabelOffsetWithConnector)
Q_PROPERTY(double labelBoxRounding MEMBER m_labelBoxRounding READ getLabelBoxRounding WRITE setLabelBoxRounding)
Q_PROPERTY(double labelXPadding MEMBER m_labelXPadding READ getLabelXPadding WRITE setLabelXPadding)
Q_PROPERTY(double labelYPadding MEMBER m_labelYPadding READ getLabelYPadding WRITE setLabelYPadding)
Q_PROPERTY(JKQTPGraphLabelPosition labelPosition MEMBER m_labelPosition READ getLabelPosition WRITE setLabelPosition)
Q_PROPERTY(bool drawLabelBoxFrame MEMBER m_drawLabelBoxFrame READ drawsLabelBoxFrame WRITE setDrawLabelBoxFrame)
Q_PROPERTY(JKQTPGraphLabelBoxType labelBoxType MEMBER m_labelBoxType READ getLabelBoxType WRITE setLabelBoxType)
#endif
protected:
/** \brief describes details about the geometry of a label, used by calcLabelGeometry() */
struct LabelGeometry {
inline LabelGeometry():
labelOffsetPx(0.0),
padX(0.0),
padY(0.0),
lw(0.0),
label(""),
textSize(),
textRect(),
boxRect(),
boxpos(BoxTop)
{ };
double labelOffsetPx;
double padX;
double padY;
double lw;
QString label;
JKQTMathTextNodeSize textSize;
QRectF textRect;
QRectF boxRect;
enum BoxPos {
BoxLeft,
BoxRight,
BoxTop,
BoxBottom
};
BoxPos boxpos;
};
/** \brief calculate everything that is necessary to draw a label, including its box
*
* \brief painter the JKQTPEnhancedPainter to use for drawing
* \brief xDataPixel position of the labeled datapoint in (screen) pixels
* \brief xData x- and y-coordinate of the datapoint (needed for some JKQTPGraphLabelPosition)
* \brief contents the text to be rendered
* \brief parent the JKQTPBasePlotter in whos context we are drawing (e.g. needed to render \a contents )
*
*/
LabelGeometry calcLabelGeometry(JKQTPEnhancedPainter& painter, const QPointF& xDataPixel, const QPointF& xData, const QString& contents, JKQTBasePlotter *parent) const;
private:
/** \brief offset of the box rectangle to the actual data point location [pt], this is used for simple boxes and is a rather close distance (e.g. JKQTPGLSimpleBox)
*
* \see setLabelOffset(), getLabelOffset(), setLabelOffsetWithConnector(), getLabelOffsetWithConnector()
*/
double m_labelOffset;
/** \brief offset of the box rectangle to the actual data point location [pt], this variant is used when a visible connector is shown (e.g. JKQTPGLSimpleBoxAndLine)
*
* \see setLabelOffsetWithConnector(), getLabelOffsetWithConnector(), setLabelOffset(), getLabelOffset()
*/
double m_labelOffsetWithConnector;
/** \brief rounding radius of the box rectangle (<=0 -> no rounded rectangle) [pt] */
double m_labelBoxRounding;
/** \brief padding in x-direction between label and surrounding box [pt] */
double m_labelXPadding;
/** \brief padding in y-direction between label and surrounding box [pt] */
double m_labelYPadding;
/** \brief indicates whether to draw a frame around the box */
bool m_drawLabelBoxFrame;
/** \brief position of the label
*
* \see JKQTPGraphLabelPosition for details on available options
*/
JKQTPGraphLabelPosition m_labelPosition;
/** \brief type or style of the box surrounding the label text
*
* \see JKQTPGraphLabelBoxType for details on available options
*/
JKQTPGraphLabelBoxType m_labelBoxType;
};
/** \brief display mode for the (axis) labels
* \ingroup jkqtplotter_specialgraphs_stylemixins */
enum JKQTPGraphLabelConverterType {
JKQTPGLCdecimal, /*!< \brief print the numbers in decimal notation, without using exponent characters e.g. \c "0.00123" */
JKQTPGLCscientific, /*!< \brief print the numbers in scientific notation, e.g. \c "1.23e-4" */
JKQTPGLCexponentCharacter, /*!< \brief print the numbers and show a unit character, i.e. 5&mu; for \f$ 5\cdot 10^{-6} \f$ , \c 3k for \f$ 3\cdot 10^3 \f$ ... */
JKQTPGLCexponent, /*!< \brief show numbers in exponential for, e.g. \f$ 3\cdot 10^5 \f$ ... */
JKQTPGLCdatetime, /*!< \brief show numbers as times */
JKQTPGLDefaultConverter=JKQTPGLCexponent,
};
/*! \brief This Mix-In class provides setter/getter methods, and tools for x- and y-value label formatting (i.e. double to string conversion)
\ingroup jkqtplotter_specialgraphs_stylemixins
\see JKQTPXYGraphLabels
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPXYLabelsGeneratorMixin {
#ifndef JKQTPLOTTER_WORKAROUND_QGADGET_BUG
Q_GADGET
#endif
public:
/** \brief class constructor */
explicit JKQTPXYLabelsGeneratorMixin();
virtual ~JKQTPXYLabelsGeneratorMixin();
/** \copydoc m_xDefaultPrecision */
int getXDefaultPrecision() const;
/** \copydoc m_xDefaultPrecision */
void setXDefaultPrecision(int v);
/** \copydoc m_yDefaultPrecision */
int getYDefaultPrecision() const;
/** \copydoc m_yDefaultPrecision */
void setYDefaultPrecision(int v);
/** \copydoc m_xDefaultConverter */
JKQTPGraphLabelConverterType getXDefaultConverter() const;
/** \copydoc m_xDefaultConverter */
void setXDefaultConverter(JKQTPGraphLabelConverterType v);
/** \copydoc m_yDefaultConverter */
JKQTPGraphLabelConverterType getYDefaultConverter() const;
/** \copydoc m_yDefaultConverter */
void setYDefaultConverter(JKQTPGraphLabelConverterType v);
/** \copydoc m_xValueLabelFormat */
QString getXValueLabelFormat() const;
/** \copydoc m_xValueLabelFormat */
void setXValueLabelFormat(const QString& v);
/** \copydoc m_yValueLabelFormat */
QString getYValueLabelFormat() const;
/** \copydoc m_yValueLabelFormat */
void setYValueLabelFormat(const QString& v);
/** \copydoc m_xyValueLabelFormat */
QString getXYValueLabelFormat() const;
/** \copydoc m_xyValueLabelFormat */
void setXYValueLabelFormat(const QString& v);
/** \copydoc m_xBelowIsZero */
double getXBelowIsZero() const;
/** \copydoc m_xBelowIsZero */
void setXBelowIsZero(double v);
/** \copydoc m_yBelowIsZero */
double getYBelowIsZero() const;
/** \copydoc m_yBelowIsZero */
void setYBelowIsZero(double v);
/** \copydoc m_xMinNoExponent */
double getXMinNoExponent() const;
/** \copydoc m_xMinNoExponent */
void setXMinNoExponent(double v);
/** \copydoc m_yMinNoExponent */
double getYMinNoExponent() const;
/** \copydoc m_yMinNoExponent */
void setYMinNoExponent(double v);
/** \copydoc m_xMaxNoExponent */
double getXMaxNoExponent() const;
/** \copydoc m_xMaxNoExponent */
void setXMaxNoExponent(double v);
/** \copydoc m_yMaxNoExponent */
double getYMaxNoExponent() const;
/** \copydoc m_yMaxNoExponent */
void setYMaxNoExponent(double v);
/** \copydoc m_xDateTimeFormmat */
QString getXDateTimeFormmat() const;
/** \copydoc m_xDateTimeFormmat */
void setXDateTimeFormmat(const QString& v);
/** \copydoc m_yDateTimeFormmat */
QString getYDateTimeFormmat() const;
/** \copydoc m_yDateTimeFormmat */
void setYDateTimeFormmat(const QString& v);
protected:
/** \brief default label generator for x-value only */
QString generateDefaultXLabel(double x, double y, int index) const;
/** \brief default label generator for y-value only */
QString generateDefaultYLabel(double x, double y, int index) const;
/** \brief default label generator for x- and y-value */
QString generateDefaultXYLabel(double x, double y, int index) const;
/** \brief converts \a x to a string, using several of the formatting properties set in this class for x-values */
QString xValToString(double x) const;
/** \brief converts \a y to a string, using several of the formatting properties set in this class for y-values */
QString yValToString(double y) const;
/** \rief converts \a x to a QString, using the provided options */
static QString valToString(double x, JKQTPGraphLabelConverterType m_xDefaultConverter, int m_xDefaultPrecision, double m_xBelowIsZero, double m_xMinNoExponent, double m_xMaxNoExponent, const QString& m_xDateTimeFormat);
private:
/** \brief format string for the x-label, use \c %1 as placeholder for the numeric value */
QString m_xValueLabelFormat;
/** \brief format string for the y-label, use \c %1 as placeholder for the numeric value */
QString m_yValueLabelFormat;
/** \brief format string for the x/y-label, use \c %1 as placeholder for the numeric value of x and \c %2 for y */
QString m_xyValueLabelFormat;
/** \brief type of number to string conversion for x-values */
JKQTPGraphLabelConverterType m_xDefaultConverter;
/** \brief type of number to string conversion for y-values */
JKQTPGraphLabelConverterType m_yDefaultConverter;
/** \brief default precision for x-labels */
int m_xDefaultPrecision;
/** \brief default precision for x-labels */
int m_yDefaultPrecision;
/** \brief x-values below this value are treated as exactly 0 */
double m_xBelowIsZero;
/** \brief y-values below this value are treated as exactly 0 */
double m_yBelowIsZero;
/** \brief x-values below this value will be shown in exponent notation, above in decimal notation */
double m_xMinNoExponent;
/** \brief y-values below this value will be shown in exponent notation, above in decimal notation */
double m_yMinNoExponent;
/** \brief x-values above this value will be shown in exponent notation, below in decimal notation */
double m_xMaxNoExponent;
/** \brief y-values above this value will be shown in exponent notation, below in decimal notation */
double m_yMaxNoExponent;
/** \brief format string for datetime -> string conversion of x-values */
QString m_xDateTimeFormat;
/** \brief format string for datetime -> string conversion of y-value */
QString m_yDateTimeFormat;
};
#endif // jkqtpgraphlabelstylemixin_H

View File

@ -34,7 +34,7 @@
/*! \brief Styling Mix-In for Violinplots
\ingroup jkqtplotter_basegraphs_stylemixins
\ingroup jkqtplotter_specialgraphs_stylemixins
\image html JKQTPViolinplotHorizontalElement_elements.png

View File

@ -36,13 +36,22 @@ JKQTPGraphLineStyleMixin::JKQTPGraphLineStyleMixin()
void JKQTPGraphLineStyleMixin::initLineStyle(JKQTBasePlotter* parent, int &parentPlotStyle, JKQTPPlotStyleType styletype)
{
if (parent) { // get style settings from parent object
if (parentPlotStyle<0) parentPlotStyle=parent->getNextStyle();
const JKQTBasePlotter::JKQTPPen pen=parent->getPlotStyle(parentPlotStyle, styletype);
m_linePen.setColor(pen.color());
m_linePen.setStyle(pen.style());
m_lineWidth=pen.widthF();
m_highlightingLineColor=getLineColor();
m_highlightingLineColor.setAlphaF(0.5);
if (styletype==JKQTPPlotStyleType::Annotation) {
m_linePen=QPen(parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultLineStyle);
m_linePen.setColor(parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultColor);
m_linePen.setWidthF(parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultLineWidth);
m_lineWidth=m_linePen.widthF();
m_highlightingLineColor=getLineColor();
m_highlightingLineColor.setAlphaF(0.5);
} else {
if (parentPlotStyle<0) parentPlotStyle=parent->getNextStyle();
const JKQTBasePlotter::JKQTPPen pen=parent->getPlotStyle(parentPlotStyle, styletype);
m_linePen.setColor(pen.color());
m_linePen.setStyle(pen.style());
m_lineWidth=pen.widthF();
m_highlightingLineColor=getLineColor();
m_highlightingLineColor.setAlphaF(0.5);
}
}
}
@ -219,14 +228,22 @@ JKQTPGraphSymbolStyleMixin::JKQTPGraphSymbolStyleMixin()
void JKQTPGraphSymbolStyleMixin::initSymbolStyle(JKQTBasePlotter *parent, int& parentPlotStyle, JKQTPPlotStyleType styletype)
{
if (parent) { // get style settings from parent object
if (parentPlotStyle<0) parentPlotStyle=parent->getNextStyle();
const JKQTBasePlotter::JKQTPPen pen=parent->getPlotStyle(parentPlotStyle, styletype);
m_symbolColor=pen.color();
m_symbolSize=pen.symbolSize();
m_symbolLineWidth=pen.symbolLineWidthF();
m_symbolType=pen.symbol();
m_symbolFillColor=pen.symbolFillColor();
m_symbolFontName=parent->getDefaultTextFontName();
if (styletype==JKQTPPlotStyleType::Annotation) {
m_symbolType=parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultSymbol;
m_symbolColor=parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultColor;
m_symbolLineWidth=parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultSymbolLineWidth;
m_symbolSize=parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultSymbolSize;
m_symbolFillColor=JKQTPGetDerivedColor(parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.symbolFillColorDerivationMode, m_symbolColor);
} else {
if (parentPlotStyle<0) parentPlotStyle=parent->getNextStyle();
const JKQTBasePlotter::JKQTPPen pen=parent->getPlotStyle(parentPlotStyle, styletype);
m_symbolColor=pen.color();
m_symbolSize=pen.symbolSize();
m_symbolLineWidth=pen.symbolLineWidthF();
m_symbolType=pen.symbol();
m_symbolFillColor=pen.symbolFillColor();
m_symbolFontName=parent->getDefaultTextFontName();
}
}
}
@ -395,10 +412,15 @@ void JKQTPGraphFillStyleMixin::initFillStyleInvertedColor(JKQTPGraphFillStyleMix
void JKQTPGraphFillStyleMixin::initFillStyle(JKQTBasePlotter *parent, int &parentPlotStyle, JKQTPPlotStyleType styletype)
{
if (parent) { // get style settings from parent object
if (parentPlotStyle<0) parentPlotStyle=parent->getNextStyle();
const JKQTBasePlotter::JKQTPPen pen=parent->getPlotStyle(parentPlotStyle, styletype);
m_fillColor=pen.fillColor();
m_fillBrush=pen.fillStyle().brush(m_fillColor);
if (styletype==JKQTPPlotStyleType::Annotation) {
m_fillColor=JKQTPGetDerivedColor(parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.fillColorDerivationMode, parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultColor);
m_fillBrush=parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultFillStyle.brush(m_fillColor);
} else {
if (parentPlotStyle<0) parentPlotStyle=parent->getNextStyle();
const JKQTBasePlotter::JKQTPPen pen=parent->getPlotStyle(parentPlotStyle, styletype);
m_fillColor=pen.fillColor();
m_fillBrush=pen.fillStyle().brush(m_fillColor);
}
}
}
@ -537,10 +559,14 @@ JKQTPGraphTextStyleMixin::JKQTPGraphTextStyleMixin(JKQTBasePlotter *parent)
void JKQTPGraphTextStyleMixin::initTextStyle(JKQTBasePlotter *parent, int &/*parentPlotStyle*/, JKQTPPlotStyleType styletype)
{
if (parent && styletype==JKQTPPlotStyleType::Annotation) { // get style settings from parent object
m_textFontSize=parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultFontSize;
if (parent) { // get style settings from parent object
m_textColor=parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultTextColor;
m_textFontName=parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultFontName;
if (styletype==JKQTPPlotStyleType::Annotation) {
m_textFontSize=parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultFontSize;
} else {
m_textFontSize=QApplication::font().pointSizeF();
}
}
}

BIN
screenshots/graphlabels.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB