@@ -757,7 +757,7 @@ bool ShowLegendEntries(ImPlotItemGroup& items, const ImRect& legend_bb, bool hov
757757constexpr float TICK_FILL_X = 0 .8f ;
758758constexpr float TICK_FILL_Y = 1 .0f ;
759759
760- void Locator_Default (ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void * formatter_data) {
760+ void Locator_Default (ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void * formatter_data, double * offset, int * log10_multiplier ) {
761761 if (range.Min == range.Max )
762762 return ;
763763 const int nMinor = 10 ;
@@ -768,6 +768,27 @@ void Locator_Default(ImPlotTicker& ticker, const ImPlotRange& range, float pixel
768768 const double graphmax = ceil (range.Max / interval) * interval;
769769 bool first_major_set = false ;
770770 int first_major_idx = 0 ;
771+ bool delta_mode = false ;
772+ if ((range.Max > 0 ) == (range.Min > 0 )) {
773+ double min_abs = ImMin (ImAbs (range.Min ),ImAbs (range.Max ));
774+ *log10_multiplier = (int )IM_ROUND (ImLog10 ((range.Max - range.Min )));
775+ if (*log10_multiplier < 0 ) {
776+ *log10_multiplier = *log10_multiplier - 1 ;
777+ }
778+ *log10_multiplier = ImSign (static_cast <double >(*log10_multiplier)) * IM_TRUNC (ImAbs (static_cast <double >(*log10_multiplier)/3 .)) * 3 ;
779+
780+ delta_mode = !(*log10_multiplier==0 );
781+
782+ if (delta_mode) {
783+ double ten_base = ImPow (10 .,-static_cast <double >(*log10_multiplier) + 2 * ((*log10_multiplier < 0 ) ? -1 : 1 ));
784+
785+ *offset = (range.Max > 0 ) ? floor (graphmin*ten_base) / ten_base : ceil (graphmax*ten_base) / ten_base;
786+
787+ } else {
788+ *offset = 0 ;
789+ }
790+
791+ }
771792 const int idx0 = ticker.TickCount (); // ticker may have user custom ticks
772793 ImVec2 total_size (0 ,0 );
773794 for (double major = graphmin; major < graphmax + 0.5 * interval; major += interval) {
@@ -779,12 +800,18 @@ void Locator_Default(ImPlotTicker& ticker, const ImPlotRange& range, float pixel
779800 first_major_idx = ticker.TickCount ();
780801 first_major_set = true ;
781802 }
782- total_size += ticker.AddTick (major, true , 0 , true , formatter, formatter_data).LabelSize ;
803+ char label[16 ];
804+ sprintf (label, (char *) formatter_data, (major - (delta_mode ? *offset : 0 .))* (delta_mode ? pow (10 ,-*log10_multiplier) : 1 ));
805+ total_size += ticker.AddTick (major, true , 0 , true , label).LabelSize ;
806+ // total_size += ticker.AddTick(major, true, 0, true, formatter, formatter_data).LabelSize;
783807 }
784808 for (int i = 1 ; i < nMinor; ++i) {
785809 double minor = major + i * interval / nMinor;
786810 if (range.Contains (minor)) {
787- total_size += ticker.AddTick (minor, false , 0 , true , formatter, formatter_data).LabelSize ;
811+ char label[16 ];
812+ sprintf (label, (char *) formatter_data, (minor - (delta_mode ? *offset : 0 .))* (delta_mode ? pow (10 ,-*log10_multiplier) : 1 ));
813+ total_size += ticker.AddTick (minor, false , 0 , true , label).LabelSize ;
814+ // total_size += ticker.AddTick(minor, false, 0, true, formatter, formatter_data).LabelSize;
788815 }
789816 }
790817 }
@@ -837,7 +864,7 @@ void AddTicksLogarithmic(const ImPlotRange& range, int exp_min, int exp_max, int
837864 }
838865}
839866
840- void Locator_Log10 (ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void * formatter_data) {
867+ void Locator_Log10 (ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void * formatter_data, double * offset, int * log10_multiplier ) {
841868 int exp_min, exp_max, exp_step;
842869 if (CalcLogarithmicExponents (range, pixels, vertical, exp_min, exp_max, exp_step))
843870 AddTicksLogarithmic (range, exp_min, exp_max, exp_step, ticker, formatter, formatter_data);
@@ -854,7 +881,7 @@ float CalcSymLogPixel(double plt, const ImPlotRange& range, float pixels) {
854881 return (float )(0 + scaleToPixels * (plt - range.Min ));
855882}
856883
857- void Locator_SymLog (ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void * formatter_data) {
884+ void Locator_SymLog (ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void * formatter_data, double * offset, int * log10_multiplier ) {
858885 if (range.Min >= -1 && range.Max <= 1 ) {
859886 Locator_Default (ticker, range, pixels, vertical, formatter, formatter_data);
860887 }
@@ -1257,7 +1284,7 @@ inline ImPlotDateTimeSpec GetDateTimeFmt(const ImPlotDateTimeSpec* ctx, ImPlotTi
12571284 return fmt;
12581285}
12591286
1260- void Locator_Time (ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void * formatter_data) {
1287+ void Locator_Time (ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void * formatter_data, double * offset, int * log10_multiplier ) {
12611288 IM_ASSERT_USER_ERROR (vertical == false , " Cannot locate Time ticks on vertical axis!" );
12621289 (void )vertical;
12631290 // get units for level 0 and level 1 labels
@@ -2618,10 +2645,12 @@ void SetupFinish() {
26182645 const float plot_height = plot.CanvasRect .GetHeight () - pad_top - pad_bot;
26192646
26202647 // (2) get y tick labels (needed for left/right pad)
2648+ double y_offset = 0 .;
2649+ int y_log10_multiplier = 0 .;
26212650 for (int i = 0 ; i < IMPLOT_NUM_Y_AXES ; i++) {
26222651 ImPlotAxis& axis = plot.YAxis (i);
26232652 if (axis.WillRender () && axis.ShowDefaultTicks && plot_height > 0 ) {
2624- axis.Locator (axis.Ticker , axis.Range , plot_height, true , axis.Formatter , axis.FormatterData );
2653+ axis.Locator (axis.Ticker , axis.Range , plot_height, true , axis.Formatter , axis.FormatterData , &y_offset, &y_log10_multiplier );
26252654 }
26262655 }
26272656
@@ -2631,10 +2660,12 @@ void SetupFinish() {
26312660 const float plot_width = plot.CanvasRect .GetWidth () - pad_left - pad_right;
26322661
26332662 // (4) get x ticks
2663+ double x_offset = 0 .;
2664+ int x_log10_multiplier = 0 .;
26342665 for (int i = 0 ; i < IMPLOT_NUM_X_AXES ; i++) {
26352666 ImPlotAxis& axis = plot.XAxis (i);
26362667 if (axis.WillRender () && axis.ShowDefaultTicks && plot_width > 0 ) {
2637- axis.Locator (axis.Ticker , axis.Range , plot_width, false , axis.Formatter , axis.FormatterData );
2668+ axis.Locator (axis.Ticker , axis.Range , plot_width, false , axis.Formatter , axis.FormatterData , &x_offset, &x_log10_multiplier );
26382669 }
26392670 }
26402671
@@ -2754,7 +2785,28 @@ void SetupFinish() {
27542785 const ImPlotTicker& tkr = ax.Ticker ;
27552786 const bool opp = ax.IsOpposite ();
27562787 if (ax.HasLabel ()) {
2757- const char * label = plot.GetAxisLabel (ax);
2788+ const char * base_label = plot.GetAxisLabel (ax);
2789+ char label[36 ];
2790+ if (x_offset==0 . && x_log10_multiplier==0 ) {
2791+ strcpy (label, base_label);
2792+ } else {
2793+ strcpy (label, " (" );
2794+ strcat (label, base_label);
2795+ char label_offset_label[12 ];
2796+ sprintf (label_offset_label, (char *)ax.FormatterData , ImAbs (x_offset));
2797+ if (x_offset>0 ) {
2798+ strcat (label," - " );
2799+ } else if (x_offset < 0 ){
2800+ strcat (label," + " );
2801+ }
2802+ char label_log10_label[12 ];
2803+ sprintf (label_log10_label, " ) x 10^%d" , -x_log10_multiplier);
2804+ if (x_offset!=0 ) {
2805+ strcat (label, label_offset_label);
2806+ }
2807+ strcat (label, label_log10_label);
2808+ }
2809+
27582810 const ImVec2 label_size = ImGui::CalcTextSize (label);
27592811 const float label_offset = (ax.HasTickLabels () ? tkr.MaxSize .y + gp.Style .LabelPadding .y : 0 .0f )
27602812 + (tkr.Levels - 1 ) * (txt_height + gp.Style .LabelPadding .y )
@@ -2763,6 +2815,7 @@ void SetupFinish() {
27632815 opp ? ax.Datum1 - label_offset - label_size.y : ax.Datum1 + label_offset);
27642816 DrawList.AddText (label_pos, ax.ColorTxt , label);
27652817 }
2818+
27662819 if (ax.HasTickLabels ()) {
27672820 for (int j = 0 ; j < tkr.TickCount (); ++j) {
27682821 const ImPlotTick& tk = tkr.Ticks [j];
0 commit comments