Вопрос

I'm trying to figure out how to dynamically format the values on the axes of my line chart based on the multiplier.

I'm using LogAxis for both the X and Y axes, as follows:

  final LogAxis rangeAxis = new LogAxis(valueAxisLabel);
  rangeAxis.setStandardTickUnits(LogAxis.createLogTickUnits(Locale.ENGLISH));
  rangeAxis.setRange(0.01, 10.0);  //10 mOhms to 10 Ohms
  plot.setRangeAxis(rangeAxis);

  final LogAxis domainAxis = new LogAxis(frequencyAxisLabel);
  domainAxis.setStandardTickUnits(LogAxis.createLogTickUnits(Locale.ENGLISH));
  domainAxis.setRange(100, 10000000); //100Hz to 10MHz
  plot.setDomainAxis(domainAxis);

I currently have the following values on my Y axis:
0.01, 0.1, 1, 10
But would like it to display as
10mOhm, 100mOhm, 1Ohm, 10Ohm

and on the X axis I have
100, 1,000, 10,000, 100,000, 1,000,000, 10,000,000
but would like to see
100Hz, 1kHz, 10kHz, 100kHz, 1MHz, 10MHz

I know you can override the NumberFormat used on the axis, but I haven't found a way to do so to where the NumberFormat is overridden dynamically based on the value like this. Is this possible? Do I need to extend NumberFormat to do this?

EDIT: Per the accepted answer, I extended NumberFormat as follows (Note that the implementation isn't complete but rather hacked for quick demo purposes for my boss)

public class UnitNumberFormat extends NumberFormat
{
   /**
    * 
    */
   private static final long serialVersionUID = -8544764432101798895L;

   private UnitValue unitValue;


   public UnitNumberFormat(UnitValue unitValue)
   {
      super();
      this.unitValue = unitValue;
   }


   /*
    * (non-Javadoc)
    * @see java.text.NumberFormat#format(double, java.lang.StringBuffer,
    * java.text.FieldPosition)
    */
   @Override
   public StringBuffer format(double number, StringBuffer toAppendTo, FieldPosition pos)
   {
      StringBuffer formattedValue = new StringBuffer();
      BigDecimal bd = new BigDecimal(number);
      BigDecimal multiplier = new BigDecimal(1);
      String multiplierString = "";
      if(number < 1 && number > 0)
      {
         multiplier = new BigDecimal(1000);
         multiplierString = "m";
      }
      else if(number < 1000 && number >= 1)
      {
         multiplier = new BigDecimal(1);
         multiplierString = "";
      }
      else if(number < 1000000 && number >= 1000)
      {
         multiplier = new BigDecimal(1. / 1000);
         multiplierString = "k";
      }
      else if(number < 1000000000 && number >= 1000000)
      {
         multiplier = new BigDecimal(1. / 1000000);
         multiplierString = "M";
      }
      else
      {
         throw new NumberFormatException("This formatter doesn't yet support values beyond Mega");
      }

      bd = bd.multiply(multiplier).round(new MathContext(1, RoundingMode.HALF_UP));

      formattedValue.append(bd.toPlainString());
      formattedValue.append(" ");
      formattedValue.append(multiplierString);
      formattedValue.append(this.unitValue.getUnit());

      return formattedValue;
   }


   /*
    * (non-Javadoc)
    * @see java.text.NumberFormat#format(long, java.lang.StringBuffer,
    * java.text.FieldPosition)
    */
   @Override
   public StringBuffer format(long number, StringBuffer toAppendTo, FieldPosition pos)
   {
      return null;
   }


   /*
    * (non-Javadoc)
    * @see java.text.NumberFormat#parse(java.lang.String,
    * java.text.ParsePosition)
    */
   @Override
   public Number parse(String source, ParsePosition parsePosition)
   {
      return null;
   }

}

and UnitValue is as follows:

public enum UnitValue {
   HERTZ("Hz"),

   OHMS("Ω"),

   ;

   private final String unit;


   private UnitValue(String unit)
   {
      this.unit = unit;
   }


   /**
    * @return the unit
    */
   public String getUnit()
   {
      return unit;
   }
}
Это было полезно?

Решение

Yes you do need to subclass NumberFormat there is an example here

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top