Add normalize to imshow and colorbar

This commit is contained in:
wyq 2022-01-20 23:55:30 +08:00
parent 4e44a4ba1e
commit fe36eee6dd
23 changed files with 1311 additions and 194 deletions

View File

@ -72,8 +72,8 @@
<orderEntry type="module" module-name="meteoinfo-dataframe" />
<orderEntry type="library" name="Maven: edu.ucar:netcdfAll:5.4.1" level="project" />
<orderEntry type="library" name="Maven: com.github.albfernandez:juniversalchardet:2.4.0" level="project" />
<orderEntry type="library" name="Maven: com.formdev:flatlaf:2.0-rc1" level="project" />
<orderEntry type="library" name="Maven: com.formdev:flatlaf-extras:2.0-rc1" level="project" />
<orderEntry type="library" name="Maven: com.formdev:flatlaf:2.0" level="project" />
<orderEntry type="library" name="Maven: com.formdev:flatlaf-extras:2.0" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: com.formdev:svgSalamander:1.1.3" level="project" />
<orderEntry type="library" name="Maven: com.itextpdf:itextpdf:5.5.13.2" level="project" />
<orderEntry type="module" module-name="meteoinfo-ui" />

View File

@ -13,11 +13,20 @@ import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import org.meteoinfo.common.*;
import org.meteoinfo.common.colors.ColorMap;
import org.meteoinfo.geo.drawing.Draw;
import org.meteoinfo.geometry.colors.BoundaryNorm;
import org.meteoinfo.geometry.colors.ExtendType;
import org.meteoinfo.geometry.colors.LogNorm;
import org.meteoinfo.geometry.colors.Normalize;
import org.meteoinfo.geometry.legend.*;
import org.meteoinfo.geometry.shape.ShapeTypes;
@ -38,6 +47,7 @@ public class ChartColorBar extends ChartLegend {
private Color tickColor;
private boolean drawMinLabel;
private boolean drawMaxLabel;
private ExtendType extendType;
// </editor-fold>
// <editor-fold desc="Constructor">
@ -59,6 +69,8 @@ public class ChartColorBar extends ChartLegend {
this.tickColor = Color.black;
this.drawMinLabel = false;
this.drawMaxLabel = false;
this.extendType = ExtendType.NEITHER;
this.setLegendScheme(ls);
}
// </editor-fold>
@ -263,6 +275,39 @@ public class ChartColorBar extends ChartLegend {
this.tickLabelColor = value;
}
/**
* Set legend scheme
*
* @param value Legend scheme
*/
@Override
public void setLegendScheme(LegendScheme value) {
this.legendScheme = value;
Normalize normalize = this.legendScheme.getNormalize();
if (normalize != null) {
double min = normalize.getMinValue();
double max = normalize.getMaxValue();
double[] tickValues;
if (normalize instanceof LogNorm) {
tickValues = MIMath.getIntervalValues_Log(min, max);
} else {
tickValues = MIMath.getIntervalValues(min, max);
}
this.tickLocations = Arrays.stream(tickValues).boxed().collect(Collectors.toList());
this.tickLabels = new ArrayList<>();
if (normalize instanceof LogNorm) {
for (double v : this.tickLocations) {
int e = (int) Math.floor(Math.log10(v));
this.tickLabels.add(new ChartText("$10^{" + String.valueOf(e) + "}$"));
}
} else {
for (double v : this.tickLocations) {
this.tickLabels.add(new ChartText(DataConvert.removeTailingZeros(String.valueOf(v))));
}
}
}
}
/**
* Get if draw minimum value label
*
@ -299,6 +344,30 @@ public class ChartColorBar extends ChartLegend {
this.drawMaxLabel = value;
}
/**
* Get extend type
* @return Extend type
*/
public ExtendType getExtendType() {
return this.extendType;
}
/**
* Set extend type
* @param value Extend type
*/
public void setExtendType(ExtendType value) {
this.extendType = value;
}
/**
* Set extend type
* @param value Extend type string
*/
public void setExtendType(String value) {
this.extendType = ExtendType.valueOf(value.toUpperCase());
}
// </editor-fold>
// <editor-fold desc="Method">
/**
@ -323,10 +392,16 @@ public class ChartColorBar extends ChartLegend {
g.setStroke(new BasicStroke(1));
switch (this.orientation) {
case HORIZONTAL:
this.drawHorizontalBarLegend(g, legendScheme);
if (legendScheme.getColorMap() != null)
this.drawHorizontal(g, legendScheme);
else
this.drawHorizontalBarLegend(g, legendScheme);
break;
case VERTICAL:
this.drawVerticalBarLegend(g, legendScheme);
if (legendScheme.getColorMap() != null)
this.drawVertical(g, legendScheme);
else
this.drawVerticalBarLegend(g, legendScheme);
break;
}
@ -381,6 +456,182 @@ public class ChartColorBar extends ChartLegend {
}
}
private void drawHorizontal(Graphics2D g, LegendScheme ls) {
PointF aP = new PointF(0, 0);
PointF sP = new PointF(0, 0);
String caption;
ColorMap colorMap = ls.getColorMap();
Normalize normalize = ls.getNormalize();
int bNum = colorMap.getColorCount();
if (normalize instanceof BoundaryNorm) {
bNum = ((BoundaryNorm) normalize).getNRegions();
}
this.barHeight = (float) this.legendWidth / this.aspect;
float minMaxWidth = this.legendWidth;
float x_shift = 0;
switch (this.extendType) {
case MIN:
minMaxWidth -= barHeight;
x_shift += barHeight;
break;
case MAX:
minMaxWidth -= barHeight;
break;
case BOTH:
minMaxWidth -= barHeight * 2;
x_shift += barHeight;
break;
}
barWidth = minMaxWidth / bNum;
float y_shift = 0;
if (this.label != null){
switch (this.labelLocation){
case "top":
case "in":
y_shift = this.label.getDimension(g).height + 5;
break;
}
}
//Draw color polygons
aP.Y = y_shift;
Color[] colors = colorMap.getColors(bNum);
switch (this.extendType) {
case MIN:
case BOTH:
g.setColor(colors[0]);
Path2D p = new Path2D.Float();
p.moveTo(aP.X, aP.Y + barHeight / 2);
p.lineTo(aP.X + barHeight, aP.Y);
p.lineTo(aP.X + barHeight, aP.Y + barHeight);
p.lineTo(aP.X, aP.Y + barHeight / 2);
p.closePath();
g.fill(p);
aP.X += barHeight;
break;
}
for (int i = 0; i < bNum; i++) {
g.setColor(colors[i]);
Rectangle2D rect = new Rectangle2D.Float(aP.X - 1, aP.Y, barWidth + 1, barHeight);
g.fill(rect);
aP.X += barWidth;
}
switch (this.extendType) {
case MAX:
case BOTH:
g.setColor(colors[bNum - 1]);
Path2D p = new Path2D.Float();
p.moveTo(aP.X, aP.Y);
p.lineTo(aP.X, aP.Y + barHeight);
p.lineTo(aP.X + barHeight, aP.Y + barHeight / 2);
p.lineTo(aP.X, aP.Y);
p.closePath();
g.fill(p);
break;
}
//Draw neatline
g.setStroke(new BasicStroke(this.neatLineSize));
g.setColor(this.neatLineColor);
switch (this.extendType) {
case NEITHER:
g.draw(new Rectangle.Double(0, y_shift, this.barWidth * bNum, this.barHeight));
break;
case BOTH:
Path2D p = new Path2D.Float();
p.moveTo(0, this.barHeight / 2 + y_shift);
p.lineTo(this.barHeight, y_shift);
p.lineTo(this.legendWidth - barHeight, y_shift);
p.lineTo(this.legendWidth, this.barHeight / 2 + y_shift);
p.lineTo(this.legendWidth - barHeight, this.barHeight + y_shift);
p.lineTo(this.barHeight, this.barHeight + y_shift);
p.closePath();
g.draw(p);
break;
case MIN:
p = new Path2D.Float();
p.moveTo(0, this.barHeight / 2 + y_shift);
p.lineTo(this.barHeight, y_shift);
p.lineTo(this.legendWidth, y_shift);
p.lineTo(this.legendWidth, this.barHeight + y_shift);
p.lineTo(this.barHeight, this.barHeight + y_shift);
p.lineTo(0, this.barHeight / 2 + y_shift);
p.closePath();
g.draw(p);
break;
case MAX:
p = new Path2D.Float();
p.moveTo(0, y_shift);
p.lineTo(0, this.barHeight + y_shift);
p.lineTo(this.legendWidth - barHeight, this.barHeight + y_shift);
p.lineTo(this.legendWidth, this.barHeight / 2 + y_shift);
p.lineTo(this.legendWidth - barHeight, y_shift);
p.lineTo(0, y_shift);
p.closePath();
g.draw(p);
break;
}
//Draw tick and label
float tickLen = this.tickLength;
if (this.insideTick) {
if (this.barHeight < tickLen) {
tickLen = (int) this.barHeight;
}
}
g.setStroke(new BasicStroke(this.tickWidth));
g.setFont(tickLabelFont);
g.setColor(this.tickColor);
aP.Y = barHeight + y_shift;
for (int i = 0; i < this.tickLocations.size(); i++) {
sP.X = x_shift + minMaxWidth * normalize.apply(this.tickLocations.get(i)).floatValue();
sP.Y = aP.Y;
g.setColor(this.tickColor);
this.drawTickLine(g, sP, tickLen, true, 0);
String label = this.tickLabels.get(i).getText();
g.setColor(this.tickLabelColor);
if (this.tickLabelAngle == 0) {
Draw.drawString(g, sP.X, sP.Y, label, XAlign.CENTER, YAlign.TOP, this.tickLabelAngle, true);
} else if (this.tickLabelAngle < 45) {
Draw.drawString(g, sP.X, sP.Y, label, XAlign.RIGHT, YAlign.TOP, this.tickLabelAngle, true);
} else {
Draw.drawString(g, sP.X, sP.Y, label, XAlign.RIGHT, YAlign.CENTER, this.tickLabelAngle, true);
}
}
//Draw label
double sx, sy;
if (this.label != null) {
g.setFont(this.label.getFont());
g.setColor(this.label.getColor());
switch (this.labelLocation) {
case "top":
case "in":
sx = this.legendWidth * 0.5;
sy = 2;
Draw.drawString(g, sx, sy, label.getText(), XAlign.CENTER, YAlign.TOP, label.isUseExternalFont());
break;
case "right":
sx = this.legendWidth + 5;
sy = this.barHeight * 0.5;
Draw.drawString(g, sx, sy, label.getText(), XAlign.LEFT, YAlign.CENTER, label.isUseExternalFont());
break;
case "left":
sx = -5;
sy = this.barHeight * 0.5;
Draw.drawString(g, sx, sy, label.getText(), XAlign.RIGHT, YAlign.CENTER, label.isUseExternalFont());
break;
default:
sx = this.legendWidth * 0.5;
sy = this.height - 2;
Draw.drawString(g, sx, sy, label.getText(), XAlign.CENTER, YAlign.BOTTOM, label.isUseExternalFont());
break;
}
}
}
private void drawHorizontalBarLegend(Graphics2D g, LegendScheme aLS) {
PointD aP = new PointD(0, 0);
PointD sP = new PointD(0, 0);
@ -426,8 +677,8 @@ public class ChartColorBar extends ChartLegend {
}
}
this._hBarHeight = (double) this.legendWidth / this.aspect;
_vBarWidth = (double) this.legendWidth / bNum;
this.barHeight = (float) this.legendWidth / this.aspect;
barWidth = (float) this.legendWidth / bNum;
float y_shift = 0;
if (this.label != null){
switch (this.labelLocation){
@ -472,30 +723,30 @@ public class ChartColorBar extends ChartLegend {
if (aLS.getShapeType() == ShapeTypes.POLYGON) {
PolygonBreak aPGB = (PolygonBreak) aLS.getLegendBreaks().get(idx).clone();
aPGB.setDrawOutline(false);
Draw.drawPolygonSymbol(aP.X, aP.Y, _vBarWidth, _hBarHeight, aPGB, g);
Draw.drawPolygonSymbol(aP.X, aP.Y, barWidth, barHeight, aPGB, g);
} else {
Draw.drawPolygonSymbol(aP.X, aP.Y, FillColor, OutlineColor, _vBarWidth,
_hBarHeight, DrawFill, DrawOutline, g);
Draw.drawPolygonSymbol(aP.X, aP.Y, FillColor, OutlineColor, barWidth,
barHeight, DrawFill, DrawOutline, g);
}
} else {
double extendw = _vBarWidth;
double extendw = barWidth;
if (this.autoExtendFrac) {
extendw = _hBarHeight;
extendw = barHeight;
}
if (i == 0) {
PointD[] Points = new PointD[4];
Points[0] = new PointD();
Points[0].X = _vBarWidth - extendw;
Points[0].Y = aP.Y + _hBarHeight * 0.5;
Points[0].X = barWidth - extendw;
Points[0].Y = aP.Y + barHeight * 0.5;
Points[1] = new PointD();
Points[1].X = _vBarWidth;
Points[1].X = barWidth;
Points[1].Y = aP.Y;
Points[2] = new PointD();
Points[2].X = _vBarWidth;
Points[2].Y = aP.Y + _hBarHeight;
Points[2].X = barWidth;
Points[2].Y = aP.Y + barHeight;
Points[3] = new PointD();
Points[3].X = _vBarWidth - extendw;
Points[3].Y = aP.Y + _hBarHeight * 0.5;
Points[3].X = barWidth - extendw;
Points[3].Y = aP.Y + barHeight * 0.5;
if (aLS.getShapeType() == ShapeTypes.POLYGON) {
PolygonBreak aPGB = (PolygonBreak) aLS.getLegendBreaks().get(idx).clone();
aPGB.setDrawOutline(false);
@ -506,17 +757,17 @@ public class ChartColorBar extends ChartLegend {
} else if (i == bNum - 1) {
PointD[] Points = new PointD[4];
Points[0] = new PointD();
Points[0].X = i * _vBarWidth - 1.0f;
Points[0].Y = aP.Y + _hBarHeight;
Points[0].X = i * barWidth - 1.0f;
Points[0].Y = aP.Y + barHeight;
Points[1] = new PointD();
Points[1].X = i * _vBarWidth - 1.0f;
Points[1].X = i * barWidth - 1.0f;
Points[1].Y = aP.Y;
Points[2] = new PointD();
Points[2].X = i * _vBarWidth + extendw;
Points[2].Y = aP.Y + _hBarHeight * 0.5;
Points[2].X = i * barWidth + extendw;
Points[2].Y = aP.Y + barHeight * 0.5;
Points[3] = new PointD();
Points[3].X = i * _vBarWidth - 1.0f;
Points[3].Y = aP.Y + _hBarHeight;
Points[3].X = i * barWidth - 1.0f;
Points[3].Y = aP.Y + barHeight;
if (aLS.getShapeType() == ShapeTypes.POLYGON) {
PolygonBreak aPGB = (PolygonBreak) aLS.getLegendBreaks().get(idx).clone();
aPGB.setDrawOutline(false);
@ -527,41 +778,41 @@ public class ChartColorBar extends ChartLegend {
} else if (aLS.getShapeType() == ShapeTypes.POLYGON) {
PolygonBreak aPGB = (PolygonBreak) aLS.getLegendBreaks().get(idx).clone();
aPGB.setDrawOutline(false);
Draw.drawPolygonSymbol(aP.X, aP.Y, _vBarWidth, _hBarHeight, aPGB, g);
Draw.drawPolygonSymbol(aP.X, aP.Y, barWidth, barHeight, aPGB, g);
} else {
Draw.drawPolygonSymbol(aP.X, aP.Y, FillColor, OutlineColor, _vBarWidth,
_hBarHeight, DrawFill, DrawOutline, g);
Draw.drawPolygonSymbol(aP.X, aP.Y, FillColor, OutlineColor, barWidth,
barHeight, DrawFill, DrawOutline, g);
}
}
}
aP.X += _vBarWidth;
aP.X += barWidth;
}
//Draw neatline
g.setStroke(new BasicStroke(this.neatLineSize));
g.setColor(this.neatLineColor);
if (this.extendRect) {
g.draw(new Rectangle.Double(0, y_shift, this._vBarWidth * bNum, this._hBarHeight));
g.draw(new Rectangle.Double(0, y_shift, this.barWidth * bNum, this.barHeight));
} else {
double extendw = _vBarWidth;
double extendw = barWidth;
if (this.autoExtendFrac) {
extendw = _hBarHeight;
extendw = barHeight;
}
Path2D p = new Path2D.Double();
p.moveTo(_vBarWidth - extendw, this._hBarHeight / 2 + y_shift);
p.lineTo(this._vBarWidth, y_shift);
p.lineTo(this._vBarWidth * (bNum - 1), y_shift);
p.lineTo(this._vBarWidth * (bNum - 1) + extendw, this._hBarHeight / 2 + y_shift);
p.lineTo(this._vBarWidth * (bNum - 1), this._hBarHeight + y_shift);
p.lineTo(this._vBarWidth, this._hBarHeight + y_shift);
p.moveTo(barWidth - extendw, this.barHeight / 2 + y_shift);
p.lineTo(this.barWidth, y_shift);
p.lineTo(this.barWidth * (bNum - 1), y_shift);
p.lineTo(this.barWidth * (bNum - 1) + extendw, this.barHeight / 2 + y_shift);
p.lineTo(this.barWidth * (bNum - 1), this.barHeight + y_shift);
p.lineTo(this.barWidth, this.barHeight + y_shift);
p.closePath();
g.draw(p);
}
//Draw tick and label
aP.X = -_vBarWidth / 2;
aP.X = -barWidth / 2;
float tickLen = this.tickLength;
if (this.insideTick) {
if (this._hBarHeight < tickLen) {
tickLen = (int) this._hBarHeight;
if (this.barHeight < tickLen) {
tickLen = (int) this.barHeight;
}
}
g.setStroke(new BasicStroke(this.tickWidth));
@ -569,8 +820,8 @@ public class ChartColorBar extends ChartLegend {
g.setColor(this.tickColor);
idx = 0;
for (int i = 0; i < bNum; i++) {
aP.X += _vBarWidth;
aP.Y = _hBarHeight / 2 + y_shift;
aP.X += barWidth;
aP.Y = barHeight / 2 + y_shift;
if (labelIdxs.contains(i)) {
ColorBreak cb = aLS.getLegendBreaks().get(i);
if (this.autoTick) {
@ -585,7 +836,7 @@ public class ChartColorBar extends ChartLegend {
if (aLS.getLegendType() == LegendType.UNIQUE_VALUE) {
sP.X = aP.X;
sP.Y = aP.Y + _hBarHeight / 2 + 5;
sP.Y = aP.Y + barHeight / 2 + 5;
g.setColor(this.tickLabelColor);
if (this.tickLabelAngle == 0) {
Draw.drawString(g, sP.X, sP.Y, caption, XAlign.CENTER, YAlign.TOP, this.tickLabelAngle, true);
@ -595,8 +846,8 @@ public class ChartColorBar extends ChartLegend {
Draw.drawString(g, sP.X, sP.Y, caption, XAlign.RIGHT, YAlign.CENTER, this.tickLabelAngle, true);
}
} else {
sP.X = aP.X + _vBarWidth / 2;
sP.Y = aP.Y + _hBarHeight / 2;
sP.X = aP.X + barWidth / 2;
sP.Y = aP.Y + barHeight / 2;
PointD ssP = (PointD)sP.clone();
if (this.autoTick) {
if (i < bNum - 1) {
@ -612,16 +863,16 @@ public class ChartColorBar extends ChartLegend {
}
if (this.drawMinLabel && i == 0) {
g.setColor(this.tickColor);
this.drawTickLine(g, ssP, tickLen, true, -this._vBarWidth);
this.drawTickLine(g, ssP, tickLen, true, -this.barWidth);
caption = DataConvert.removeTailingZeros(cb.getStartValue().toString());
g.setColor(this.tickLabelColor);
//Draw.drawString(g, ssP.X - this._vBarWidth, ssP.Y, caption, XAlign.CENTER, YAlign.TOP, this.tickLabelAngle, true);
//Draw.drawString(g, ssP.X - this.barWidth, ssP.Y, caption, XAlign.CENTER, YAlign.TOP, this.tickLabelAngle, true);
if (this.tickLabelAngle == 0) {
Draw.drawString(g, ssP.X - this._vBarWidth, ssP.Y, caption, XAlign.CENTER, YAlign.TOP, this.tickLabelAngle, true);
Draw.drawString(g, ssP.X - this.barWidth, ssP.Y, caption, XAlign.CENTER, YAlign.TOP, this.tickLabelAngle, true);
} else if (this.tickLabelAngle < 45) {
Draw.drawString(g, ssP.X - this._vBarWidth, ssP.Y, caption, XAlign.RIGHT, YAlign.TOP, this.tickLabelAngle, true);
Draw.drawString(g, ssP.X - this.barWidth, ssP.Y, caption, XAlign.RIGHT, YAlign.TOP, this.tickLabelAngle, true);
} else {
Draw.drawString(g, ssP.X - this._vBarWidth, ssP.Y, caption, XAlign.RIGHT, YAlign.CENTER, this.tickLabelAngle, true);
Draw.drawString(g, ssP.X - this.barWidth, ssP.Y, caption, XAlign.RIGHT, YAlign.CENTER, this.tickLabelAngle, true);
}
}
} else if (this.drawMaxLabel) {
@ -639,15 +890,15 @@ public class ChartColorBar extends ChartLegend {
} else {
if (i == 0 && this.tickLocations.get(idx) == Double.parseDouble(cb.getStartValue().toString())) {
g.setColor(this.tickColor);
this.drawTickLine(g, sP, tickLen, true, -this._vBarWidth);
this.drawTickLine(g, sP, tickLen, true, -this.barWidth);
g.setColor(this.tickLabelColor);
//Draw.drawString(g, sP.X - this._vBarWidth, sP.Y, caption, XAlign.CENTER, YAlign.TOP, this.tickLabelAngle, true);
//Draw.drawString(g, sP.X - this.barWidth, sP.Y, caption, XAlign.CENTER, YAlign.TOP, this.tickLabelAngle, true);
if (this.tickLabelAngle == 0) {
Draw.drawString(g, sP.X - this._vBarWidth, sP.Y, caption, XAlign.CENTER, YAlign.TOP, this.tickLabelAngle, true);
Draw.drawString(g, sP.X - this.barWidth, sP.Y, caption, XAlign.CENTER, YAlign.TOP, this.tickLabelAngle, true);
} else if (this.tickLabelAngle < 45) {
Draw.drawString(g, sP.X - this._vBarWidth, sP.Y, caption, XAlign.RIGHT, YAlign.TOP, this.tickLabelAngle, true);
Draw.drawString(g, sP.X - this.barWidth, sP.Y, caption, XAlign.RIGHT, YAlign.TOP, this.tickLabelAngle, true);
} else {
Draw.drawString(g, sP.X - this._vBarWidth, sP.Y, caption, XAlign.RIGHT, YAlign.CENTER, this.tickLabelAngle, true);
Draw.drawString(g, sP.X - this.barWidth, sP.Y, caption, XAlign.RIGHT, YAlign.CENTER, this.tickLabelAngle, true);
}
} else {
g.setColor(this.tickColor);
@ -681,12 +932,12 @@ public class ChartColorBar extends ChartLegend {
break;
case "right":
sx = this.legendWidth + 5;
sy = this._hBarHeight * 0.5;
sy = this.barHeight * 0.5;
Draw.drawString(g, sx, sy, label.getText(), XAlign.LEFT, YAlign.CENTER, label.isUseExternalFont());
break;
case "left":
sx = -5;
sy = this._hBarHeight * 0.5;
sy = this.barHeight * 0.5;
Draw.drawString(g, sx, sy, label.getText(), XAlign.RIGHT, YAlign.CENTER, label.isUseExternalFont());
break;
default:
@ -698,6 +949,178 @@ public class ChartColorBar extends ChartLegend {
}
}
private void drawVertical(Graphics2D g, LegendScheme ls) {
PointF aP = new PointF(0, 0);
PointF sP = new PointF(0, 0);
String caption;
ColorMap colorMap = ls.getColorMap();
Normalize normalize = ls.getNormalize();
int bNum = colorMap.getColorCount();
if (normalize instanceof BoundaryNorm) {
bNum = ((BoundaryNorm) normalize).getNRegions();
}
this.barWidth = (float) this.legendHeight / this.aspect;
float minMaxHeight = this.legendHeight;
float y_shift = 0;
switch (this.extendType) {
case MIN:
minMaxHeight -= barWidth;
y_shift += barWidth;
break;
case MAX:
minMaxHeight -= barWidth;
break;
case BOTH:
minMaxHeight -= barWidth * 2;
y_shift += barWidth;
break;
}
barHeight = minMaxHeight / bNum;
float x_shift = 0;
if (this.label != null){
switch (this.labelLocation){
case "left":
case "in":
x_shift = this.label.getDimension(g).height + 5;
break;
}
}
//Draw color polygons
aP.X = x_shift;
aP.Y = legendHeight;
Color[] colors = colorMap.getColors(bNum);
switch (this.extendType) {
case MIN:
case BOTH:
g.setColor(colors[0]);
Path2D p = new Path2D.Float();
p.moveTo(aP.X + barWidth / 2, aP.Y);
p.lineTo(aP.X + barWidth, aP.Y - barWidth);
p.lineTo(aP.X, aP.Y - barWidth);
p.lineTo(aP.X + barWidth / 2, aP.Y);
p.closePath();
g.fill(p);
aP.Y -= barWidth;
break;
}
for (int i = 0; i < bNum; i++) {
aP.Y -= barHeight;
g.setColor(colors[i]);
Rectangle2D rect = new Rectangle2D.Float(aP.X, aP.Y, barWidth, barHeight + 1);
g.fill(rect);
}
switch (this.extendType) {
case MAX:
case BOTH:
g.setColor(colors[bNum - 1]);
Path2D p = new Path2D.Float();
p.moveTo(aP.X, aP.Y);
p.lineTo(aP.X + barWidth, aP.Y);
p.lineTo(aP.X + barWidth / 2, aP.Y - barWidth);
p.lineTo(aP.X, aP.Y);
p.closePath();
g.fill(p);
break;
}
//Draw neatline
g.setStroke(new BasicStroke(this.neatLineSize));
g.setColor(this.neatLineColor);
switch (this.extendType) {
case NEITHER:
g.draw(new Rectangle.Double(x_shift, 0, this.barWidth, this.legendHeight));
break;
case BOTH:
Path2D p = new Path2D.Double();
p.moveTo(this.barWidth / 2 + x_shift, 0);
p.lineTo(x_shift, this.barWidth);
p.lineTo(x_shift, this.legendHeight - barWidth);
p.lineTo(this.barWidth / 2 + x_shift, legendHeight);
p.lineTo(this.barWidth + x_shift, legendHeight - barWidth);
p.lineTo(this.barWidth + x_shift, this.barWidth);
p.closePath();
g.draw(p);
break;
case MIN:
p = new Path2D.Double();
p.moveTo(x_shift, 0);
p.lineTo(this.barWidth + x_shift, 0);
p.lineTo(this.barWidth + x_shift, this.legendHeight - barWidth);
p.lineTo(this.barWidth / 2 + x_shift, legendHeight);
p.lineTo(x_shift, legendHeight - barWidth);
p.lineTo(x_shift, 0);
p.closePath();
g.draw(p);
break;
case MAX:
p = new Path2D.Double();
p.moveTo(this.barWidth / 2 + x_shift, 0);
p.lineTo(x_shift, this.barWidth);
p.lineTo(x_shift, this.legendHeight);
p.lineTo(this.barWidth + x_shift, legendHeight);
p.lineTo(this.barWidth + x_shift, this.barWidth);
p.lineTo(this.barWidth / 2 + x_shift, 0);
p.closePath();
g.draw(p);
break;
}
//Draw tick and label
float tickLen = this.tickLength;
if (this.insideTick) {
if (this.barWidth < tickLen) {
tickLen = (int) this.barWidth;
}
}
g.setStroke(new BasicStroke(this.tickWidth));
g.setFont(tickLabelFont);
g.setColor(this.tickColor);
aP.X = barWidth + x_shift;
for (int i = 0; i < this.tickLocations.size(); i++) {
sP.X = aP.X;
sP.Y = this.legendHeight - y_shift - minMaxHeight * normalize.apply(this.tickLocations.get(i)).floatValue();
g.setColor(this.tickColor);
this.drawTickLine(g, sP, tickLen, false, 0);
String label = this.tickLabels.get(i).getText();
g.setColor(this.tickLabelColor);
Draw.drawString(g, sP.X, sP.Y, label, XAlign.LEFT, YAlign.CENTER, this.tickLabelAngle, true);
}
//Draw label
double sx, sy;
if (this.label != null) {
g.setFont(this.label.getFont());
g.setColor(this.label.getColor());
Dimension dim = Draw.getStringDimension(this.label.getText(), g);
switch (this.labelLocation) {
case "top":
sx = 0;
sy = -5;
Draw.drawString(g, sx, sy, label.getText(), XAlign.LEFT, YAlign.BOTTOM, label.isUseExternalFont());
break;
case "bottom":
sx = 0;
sy = this.legendHeight + 5;
Draw.drawString(g, sx, sy, label.getText(), XAlign.LEFT, YAlign.TOP, label.isUseExternalFont());
break;
case "left":
case "in":
sx = 0;
sy = this.legendHeight * 0.5;
Draw.drawString(g, sx, sy, label.getText(), XAlign.CENTER, YAlign.TOP, 90, label.isUseExternalFont());
break;
default:
sx = this.width - dim.height;
sy = this.legendHeight * 0.5;
Draw.drawString(g, sx, sy, label.getText(), XAlign.CENTER, YAlign.TOP, 90, label.isUseExternalFont());
break;
}
}
}
private void drawVerticalBarLegend(Graphics2D g, LegendScheme aLS) {
PointD aP = new PointD(0, 0);
PointD sP = new PointD(0, 0);
@ -751,8 +1174,8 @@ public class ChartColorBar extends ChartLegend {
}
}
this._vBarWidth = (double) this.legendHeight / this.aspect;
_hBarHeight = (double) this.legendHeight / bNum;
this.barWidth = (float) this.legendHeight / this.aspect;
barHeight = (float) this.legendHeight / bNum;
aP.Y = this.legendHeight;
float x_shift = 0;
if (this.label != null){
@ -793,31 +1216,31 @@ public class ChartColorBar extends ChartLegend {
break;
}
aP.Y = aP.Y - _hBarHeight;
aP.Y = aP.Y - barHeight;
if (DrawShape) {
if (this.extendRect) {
if (aLS.getShapeType() == ShapeTypes.POLYGON) {
PolygonBreak aPGB = (PolygonBreak) aLS.getLegendBreaks().get(idx).clone();
aPGB.setDrawOutline(false);
Draw.drawPolygonSymbol(aP.X, aP.Y, _vBarWidth, _hBarHeight, aPGB, g);
Draw.drawPolygonSymbol(aP.X, aP.Y, barWidth, barHeight, aPGB, g);
} else {
Draw.drawPolygonSymbol(aP.X, aP.Y, FillColor, OutlineColor, _vBarWidth,
_hBarHeight, DrawFill, DrawOutline, g);
Draw.drawPolygonSymbol(aP.X, aP.Y, FillColor, OutlineColor, barWidth,
barHeight, DrawFill, DrawOutline, g);
}
} else if (i == 0) {
PointD[] Points = new PointD[4];
Points[0] = new PointD();
Points[0].X = aP.X + _vBarWidth * 0.5;
Points[0].X = aP.X + barWidth * 0.5;
Points[0].Y = this.legendHeight;
Points[1] = new PointD();
Points[1].X = aP.X;
Points[1].Y = aP.Y;
Points[2] = new PointD();
Points[2].X = aP.X + _vBarWidth;
Points[2].X = aP.X + barWidth;
Points[2].Y = aP.Y;
Points[3] = new PointD();
Points[3].X = aP.X + _vBarWidth * 0.5;
Points[3].X = aP.X + barWidth * 0.5;
Points[3].Y = this.legendHeight;
if (aLS.getShapeType() == ShapeTypes.POLYGON) {
PolygonBreak aPGB = (PolygonBreak) aLS.getLegendBreaks().get(idx).clone();
@ -830,16 +1253,16 @@ public class ChartColorBar extends ChartLegend {
PointD[] Points = new PointD[4];
Points[0] = new PointD();
Points[0].X = aP.X;
Points[0].Y = _hBarHeight;
Points[0].Y = barHeight;
Points[1] = new PointD();
Points[1].X = aP.X + _vBarWidth;
Points[1].Y = _hBarHeight;
Points[1].X = aP.X + barWidth;
Points[1].Y = barHeight;
Points[2] = new PointD();
Points[2].X = aP.X + _vBarWidth * 0.5;
Points[2].X = aP.X + barWidth * 0.5;
Points[2].Y = 0;
Points[3] = new PointD();
Points[3].X = aP.X;
Points[3].Y = _hBarHeight;
Points[3].Y = barHeight;
if (aLS.getShapeType() == ShapeTypes.POLYGON) {
PolygonBreak aPGB = (PolygonBreak) aLS.getLegendBreaks().get(idx).clone();
aPGB.setDrawOutline(false);
@ -850,10 +1273,10 @@ public class ChartColorBar extends ChartLegend {
} else if (aLS.getShapeType() == ShapeTypes.POLYGON) {
PolygonBreak aPGB = (PolygonBreak) aLS.getLegendBreaks().get(idx).clone();
aPGB.setDrawOutline(false);
Draw.drawPolygonSymbol(aP.X, aP.Y, _vBarWidth, _hBarHeight, aPGB, g);
Draw.drawPolygonSymbol(aP.X, aP.Y, barWidth, barHeight, aPGB, g);
} else {
Draw.drawPolygonSymbol(aP.X, aP.Y, FillColor, OutlineColor, _vBarWidth,
_hBarHeight, DrawFill, DrawOutline, g);
Draw.drawPolygonSymbol(aP.X, aP.Y, FillColor, OutlineColor, barWidth,
barHeight, DrawFill, DrawOutline, g);
}
}
}
@ -861,32 +1284,32 @@ public class ChartColorBar extends ChartLegend {
g.setStroke(new BasicStroke(this.neatLineSize));
g.setColor(this.neatLineColor);
if (this.extendRect) {
g.draw(new Rectangle.Double(x_shift, 0, this._vBarWidth, this._hBarHeight * bNum));
g.draw(new Rectangle.Double(x_shift, 0, this.barWidth, this.barHeight * bNum));
} else {
Path2D p = new Path2D.Double();
p.moveTo(this._vBarWidth / 2 + x_shift, 0);
p.lineTo(x_shift, this._hBarHeight);
p.lineTo(x_shift, (this._hBarHeight * (bNum - 1)));
p.lineTo(this._vBarWidth / 2 + x_shift, this._hBarHeight * bNum);
p.lineTo(this._vBarWidth + x_shift, this._hBarHeight * (bNum - 1));
p.lineTo(this._vBarWidth + x_shift, this._hBarHeight);
p.moveTo(this.barWidth / 2 + x_shift, 0);
p.lineTo(x_shift, this.barHeight);
p.lineTo(x_shift, (this.barHeight * (bNum - 1)));
p.lineTo(this.barWidth / 2 + x_shift, this.barHeight * bNum);
p.lineTo(this.barWidth + x_shift, this.barHeight * (bNum - 1));
p.lineTo(this.barWidth + x_shift, this.barHeight);
p.closePath();
g.draw(p);
}
//Draw ticks
g.setStroke(new BasicStroke(this.tickWidth));
aP.Y = this.legendHeight + _hBarHeight / 2;
aP.Y = this.legendHeight + barHeight / 2;
float tickLen = this.tickLength;
if (this.insideTick) {
if (this._vBarWidth < tickLen) {
tickLen = (int) this._vBarWidth;
if (this.barWidth < tickLen) {
tickLen = (int) this.barWidth;
}
}
g.setFont(tickLabelFont);
idx = 0;
for (int i = 0; i < bNum; i++) {
aP.X = _vBarWidth / 2 + x_shift;
aP.Y = aP.Y - _hBarHeight;
aP.X = barWidth / 2 + x_shift;
aP.Y = aP.Y - barHeight;
if (labelIdxs.contains(i)) {
ColorBreak cb = aLS.getLegendBreaks().get(i);
if (this.autoTick) {
@ -900,13 +1323,13 @@ public class ChartColorBar extends ChartLegend {
}
if (aLS.getLegendType() == LegendType.UNIQUE_VALUE) {
sP.X = aP.X + _vBarWidth / 2 + 5;
sP.X = aP.X + barWidth / 2 + 5;
sP.Y = aP.Y;
g.setColor(this.tickLabelColor);
Draw.drawString(g, sP.X, sP.Y, caption, XAlign.LEFT, YAlign.CENTER, this.tickLabelAngle, true);
} else {
sP.X = aP.X + _vBarWidth / 2;
sP.Y = aP.Y - _hBarHeight / 2;
sP.X = aP.X + barWidth / 2;
sP.Y = aP.Y - barHeight / 2;
PointD ssP = (PointD)sP.clone();
if (this.autoTick) {
if (i < bNum - 1) {
@ -916,10 +1339,10 @@ public class ChartColorBar extends ChartLegend {
Draw.drawString(g, sP.X, sP.Y, caption, XAlign.LEFT, YAlign.CENTER, this.tickLabelAngle, true);
if (this.drawMinLabel && i == 0) {
g.setColor(this.tickColor);
this.drawTickLine(g, ssP, tickLen, false, this._hBarHeight);
this.drawTickLine(g, ssP, tickLen, false, this.barHeight);
caption = DataConvert.removeTailingZeros(cb.getStartValue().toString());
g.setColor(this.tickLabelColor);
Draw.drawString(g, ssP.X, ssP.Y + this._hBarHeight, caption, XAlign.LEFT, YAlign.CENTER, this.tickLabelAngle, true);
Draw.drawString(g, ssP.X, ssP.Y + this.barHeight, caption, XAlign.LEFT, YAlign.CENTER, this.tickLabelAngle, true);
}
} else if (this.drawMaxLabel) {
g.setColor(this.tickColor);
@ -930,9 +1353,9 @@ public class ChartColorBar extends ChartLegend {
} else {
if (i == 0 && this.tickLocations.get(idx) == Double.parseDouble(cb.getStartValue().toString())) {
g.setColor(this.tickColor);
this.drawTickLine(g, sP, tickLen, false, this._hBarHeight);
this.drawTickLine(g, sP, tickLen, false, this.barHeight);
g.setColor(this.tickLabelColor);
Draw.drawString(g, sP.X, sP.Y + this._hBarHeight, caption, XAlign.LEFT, YAlign.CENTER, this.tickLabelAngle, true);
Draw.drawString(g, sP.X, sP.Y + this.barHeight, caption, XAlign.LEFT, YAlign.CENTER, this.tickLabelAngle, true);
} else {
g.setColor(this.tickColor);
this.drawTickLine(g, sP, tickLen, false, 0);

View File

@ -13,10 +13,7 @@
*/
package org.meteoinfo.chart;
import org.meteoinfo.common.DataConvert;
import org.meteoinfo.common.PointF;
import org.meteoinfo.common.XAlign;
import org.meteoinfo.common.YAlign;
import org.meteoinfo.common.*;
import org.meteoinfo.geo.drawing.Draw;
import com.l2fprod.common.beans.BaseBeanInfo;
import com.l2fprod.common.beans.ExtendedPropertyDescriptor;
@ -66,8 +63,8 @@ public class ChartLegend {
private float breakSpace;
private float topSpace;
private float leftSpace;
protected double _vBarWidth;
protected double _hBarHeight;
protected float barWidth;
protected float barHeight;
private int rowColNum = 1;
private boolean autoRowColNum = true;
private Dimension symbolDimension;
@ -99,8 +96,8 @@ public class ChartLegend {
breakSpace = 3;
topSpace = 5;
leftSpace = 5;
_vBarWidth = 10;
_hBarHeight = 10;
barWidth = 10;
barHeight = 10;
this.labelLocation = "out";
tickLabelFont = new Font("Arial", Font.PLAIN, 14);
this.tickLabelColor = Color.black;

View File

@ -9,6 +9,7 @@ import org.apache.commons.lang3.ArrayUtils;
import org.meteoinfo.chart.ChartText;
import org.meteoinfo.chart.jogl.pipe.PipeShape;
import org.meteoinfo.common.*;
import org.meteoinfo.common.colors.ColorMap;
import org.meteoinfo.data.GridArray;
import org.meteoinfo.data.GridData;
import org.meteoinfo.data.XYListDataset;
@ -18,6 +19,7 @@ import org.meteoinfo.geo.drawing.Draw;
import org.meteoinfo.geo.layer.ImageLayer;
import org.meteoinfo.geo.layer.VectorLayer;
import org.meteoinfo.geo.legend.LegendManage;
import org.meteoinfo.geometry.colors.Normalize;
import org.meteoinfo.geometry.graphic.Graphic;
import org.meteoinfo.geometry.graphic.GraphicCollection;
import org.meteoinfo.geometry.graphic.ImageGraphic;
@ -3063,45 +3065,74 @@ public class GraphicFactory {
int width, height, breakNum;
width = gdata.getXNum();
height = gdata.getYNum();
breakNum = ls.getBreakNum();
double[] breakValue = new double[breakNum];
Color[] breakColor = new Color[breakNum];
Color undefColor = Color.white;
for (int i = 0; i < breakNum; i++) {
breakValue[i] = Double.parseDouble(ls.getLegendBreaks().get(i).getEndValue().toString());
breakColor[i] = ls.getLegendBreaks().get(i).getColor();
if (ls.getLegendBreaks().get(i).isNoData()) {
undefColor = ls.getLegendBreaks().get(i).getColor();
}
}
Color defaultColor = breakColor[breakNum - 1]; //Last color
BufferedImage aImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
double oneValue;
Color oneColor;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
oneValue = gdata.getDoubleValue(i, j);
if (Double.isNaN(oneValue) || MIMath.doubleEquals(oneValue, gdata.missingValue)) {
oneColor = undefColor;
if (ls.getColorMap() == null) {
breakNum = ls.getValidBreakNum();
double[] breakValue = new double[breakNum];
Color[] breakColor = new Color[breakNum];
Color undefColor = Color.white;
int idx = 0;
for (ColorBreak cb : ls.getLegendBreaks()) {
if (cb.isNoData()) {
undefColor = cb.getColor();
} else {
oneColor = defaultColor;
if (ls.getLegendType() == LegendType.GRADUATED_COLOR) {
for (int k = 0; k < breakNum - 1; k++) {
if (oneValue < breakValue[k]) {
oneColor = breakColor[k];
break;
}
}
breakValue[idx] = Double.parseDouble(cb.getEndValue().toString());
breakColor[idx] = cb.getColor();
idx += 1;
}
}
Color defaultColor = breakColor[breakNum - 1]; //Last color
double oneValue;
Color oneColor;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
oneValue = gdata.getDoubleValue(i, j);
if (Double.isNaN(oneValue) || MIMath.doubleEquals(oneValue, gdata.missingValue)) {
oneColor = undefColor;
} else {
for (int k = 0; k < breakNum - 1; k++) {
if (oneValue == breakValue[k]) {
oneColor = breakColor[k];
break;
oneColor = defaultColor;
if (ls.getLegendType() == LegendType.GRADUATED_COLOR) {
for (int k = 0; k < breakNum - 1; k++) {
if (oneValue < breakValue[k]) {
oneColor = breakColor[k];
break;
}
}
} else {
for (int k = 0; k < breakNum - 1; k++) {
if (oneValue == breakValue[k]) {
oneColor = breakColor[k];
break;
}
}
}
}
aImage.setRGB(j, height - i - 1, oneColor.getRGB());
}
}
} else {
ColorMap colorMap = ls.getColorMap();
int n = colorMap.getColorCount();
Normalize normalize = ls.getNormalize();
double v;
Color fillColor = colorMap.getFillColor();
Color color;
int idx;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
v = gdata.getDoubleValue(i, j);
if (Double.isNaN(v) || MIMath.doubleEquals(v, gdata.missingValue)) {
color = fillColor;
} else {
idx = (int) (normalize.apply(v).floatValue() * n);
if (idx < 0)
idx = 0;
else if (idx >= n)
idx = n - 1;
color = colorMap.getColor(idx);
}
aImage.setRGB(j, height - i - 1, color.getRGB());
}
aImage.setRGB(j, height - i - 1, oneColor.getRGB());
}
}

View File

@ -29,6 +29,7 @@ public class ColorMap {
// <editor-fold desc="Variables">
private Color[] colors;
private String name = "";
private Color fillColor = Color.white;
final static int GRADS_RAINBOW = 0;
// </editor-fold>
@ -107,6 +108,22 @@ public class ColorMap {
public void setColors(Color[] value){
this.colors = value;
}
/**
* Get fill color
* @return Fill color
*/
public Color getFillColor() {
return this.fillColor;
}
/**
* Set fill color
* @param value Fill color
*/
public void setFillColor(Color value) {
this.fillColor = value;
}
// </editor-fold>
// <editor-fold desc="Methods">
@ -139,6 +156,23 @@ public class ColorMap {
return c;
}
}
/**
* convert normalized data value from the interval [0, 1] to the RGBA color
* @param value Normalized data value
* @return Mapped color
*/
public Color map(double value) {
if (value < 0 || value > 1) {
return this.fillColor;
}
int idx = (int)(value * this.colors.length);
if (idx == this.colors.length) {
idx = this.colors.length - 1;
}
return this.colors[idx];
}
/**
* Set color

View File

@ -87,8 +87,8 @@
<orderEntry type="library" name="Maven: org.scilab.forge:jlatexmath:1.0.7" level="project" />
<orderEntry type="library" name="Maven: org.scilab.forge:jlatexmath-font-greek:1.0.7" level="project" />
<orderEntry type="library" name="Maven: org.scilab.forge:jlatexmath-font-cyrillic:1.0.7" level="project" />
<orderEntry type="library" name="Maven: com.formdev:flatlaf:2.0-rc1" level="project" />
<orderEntry type="library" name="Maven: com.formdev:flatlaf-extras:2.0-rc1" level="project" />
<orderEntry type="library" name="Maven: com.formdev:flatlaf:2.0" level="project" />
<orderEntry type="library" name="Maven: com.formdev:flatlaf-extras:2.0" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: com.formdev:svgSalamander:1.1.3" level="project" />
<orderEntry type="library" name="Maven: org.freehep:freehep-util:2.0.2" level="project" />
<orderEntry type="library" name="Maven: org.netbeans:openide-lookup:1.9-patched-1.0" level="project" />

View File

@ -463,7 +463,8 @@ public class Draw {
// insert a border
icon.setInsets(new Insets(5, 5, 5, 5));
icon.setForeground(g.getColor());
y = y - icon.getIconHeight() + (icon.getIconHeight() - icon.getTrueIconHeight()) * 0.6f;
x = x - 5;
y = y - icon.getIconHeight() + (icon.getIconHeight() - icon.getTrueIconHeight()) * 0.5f;
//y = y - icon.getIconHeight() + size * 0.7f;
//y = y - icon.getTrueIconHeight() * 1.f;
Font font = g.getFont();

View File

@ -0,0 +1,85 @@
package org.meteoinfo.geometry.colors;
import org.meteoinfo.ndarray.Array;
import org.meteoinfo.ndarray.math.ArrayMath;
import org.meteoinfo.ndarray.math.ArrayUtil;
import java.util.List;
/**
* Generate a colormap index based on discrete intervals
*/
public class BoundaryNorm extends Normalize {
private Array boundaries;
private int nColors;
private int size;
private int nRegions; //Number of colors needed
private int offset;
private ExtendType extendType;
/**
* Constructor
* @param boundaries Boundaries
* @param nColors Number of colors
* @param extendType Extend type
*/
public BoundaryNorm(Array boundaries, int nColors, ExtendType extendType) {
super();
boundaries = boundaries.copyIfView();
this.setMinValue(boundaries.getDouble(0));
this.setMaxValue(boundaries.getDouble((int)boundaries.getSize() - 1));
this.boundaries = boundaries;
this.nColors = nColors;
this.size = (int) this.boundaries.getSize();
this.extendType = extendType;
this.nRegions = this.size - 1;
this.offset = 0;
switch (this.extendType) {
case MIN:
this.nRegions += 1;
this.offset = 1;
break;
case MAX:
this.nRegions += 1;
break;
case BOTH:
this.nRegions += 2;
this.offset = 1;
break;
}
}
/**
* Get number of color regions
* @return Number of color regions
*/
public int getNRegions() {
return this.nRegions;
}
@Override
public Number apply(double v) {
int idx = ArrayUtil.searchSorted(this.boundaries, v, true) - 1 + this.offset;
return idx;
}
@Override
public Array apply(Array a) {
Array r = ArrayUtil.searchSorted(this.boundaries, a, false);
r = ArrayMath.add(r, this.offset - 1);
return r;
}
@Override
public double inverse(double v) {
throw new UnsupportedOperationException();
}
@Override
public Array inverse(Array a) {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,8 @@
package org.meteoinfo.geometry.colors;
public enum ExtendType {
NEITHER,
BOTH,
MIN,
MAX
}

View File

@ -0,0 +1,101 @@
package org.meteoinfo.geometry.colors;
import org.meteoinfo.ndarray.Array;
import org.meteoinfo.ndarray.DataType;
import org.meteoinfo.ndarray.IndexIterator;
import org.meteoinfo.ndarray.math.ArrayMath;
import org.meteoinfo.ndarray.math.ArrayUtil;
/**
* Normalize a given value to the 0-1 range on a log scale
*/
public class LogNorm extends Normalize {
private double min;
private double max;
/**
* Constructor
* @param minValue Minimum value
* @param maxValue Maximum value
*/
public LogNorm(double minValue, double maxValue) {
this(minValue, maxValue, false);
}
/**
* Constructor
* @param minValue Minimum value
* @param maxValue Maximum value
* @param clip Clip
*/
public LogNorm(double minValue, double maxValue, boolean clip) {
this.minValue = minValue;
this.maxValue = maxValue;
this.clip = clip;
this.min = Math.log10(minValue);
this.max = Math.log10(maxValue);
}
@Override
public Number apply(double v) {
double range = max - min;
v = Math.log10(v);
v = (v - min) / range;
if (clip) {
if (v < 0)
v = 0;
else if (v > 1)
v = 1;
}
return v;
}
@Override
public Array apply(Array a) {
this.autoScaleNull(a);
Array r = Array.factory(DataType.DOUBLE, a.getShape());
IndexIterator iterA = a.getIndexIterator();
IndexIterator iterR = r.getIndexIterator();
double v, range = max - min;
if (clip) {
while (iterA.hasNext()) {
v = Math.log10(iterA.getDoubleNext());
v = (v - min) / range;
if (v < 0)
v = 0;
else if (v > 1)
v = 1;
iterR.setDoubleNext(v);
}
} else {
while (iterA.hasNext()) {
v = iterA.getDoubleNext();
v = (v - min) / range;
iterR.setDoubleNext(v);
}
}
return r;
}
@Override
public double inverse(double v) {
return Math.pow(10, min + v * (max - min));
}
@Override
public Array inverse(Array a) {
Array r = Array.factory(DataType.DOUBLE, a.getShape());
IndexIterator iterA = a.getIndexIterator();
IndexIterator iterR = r.getIndexIterator();
double v, range = max - min;
while (iterA.hasNext()) {
v = iterA.getDoubleNext();
v = Math.pow(10, min + v * range);
iterR.setDoubleNext(v);
}
return r;
}
}

View File

@ -0,0 +1,200 @@
package org.meteoinfo.geometry.colors;
import org.meteoinfo.ndarray.Array;
import org.meteoinfo.ndarray.DataType;
import org.meteoinfo.ndarray.IndexIterator;
import org.meteoinfo.ndarray.math.ArrayMath;
/**
* A class which, when called, linearly normalizes data into the [0.0, 1.0] interval.
*/
public class Normalize {
protected Double minValue;
protected Double maxValue;
protected boolean clip;
/**
* Constructor
*/
public Normalize() {
this.minValue = null;
this.maxValue = null;
this.clip = false;
}
/**
* Constructor
* @param minValue Minimum value
* @param maxValue Maximum value
*/
public Normalize(double minValue, double maxValue) {
this.minValue = minValue;
this.maxValue = maxValue;
this.clip = false;
}
/**
* Constructor
* @param minValue Minimum value
* @param maxValue Maximum value
* @param clip Clip
*/
public Normalize(double minValue, double maxValue, boolean clip) {
this.minValue = minValue;
this.maxValue = maxValue;
this.clip = clip;
}
/**
* Get minimum value
* @return Minimum value
*/
public double getMinValue() {
return this.minValue;
}
/**
* Set minimum value
* @param value Minimum value
*/
public void setMinValue(double value) {
this.minValue = value;
}
/**
* Get maximum value
* @return Maximum value
*/
public double getMaxValue() {
return this.maxValue;
}
/**
* Set maximum value
* @param value Maximum value
*/
public void setMaxValue(double value) {
this.maxValue = value;
}
/**
* Get is clip or not
* @return Clip or not
*/
public boolean isClip() {
return this.clip;
}
/**
* Set clip or not
* @param value Clip or not
*/
public void setClip(boolean value) {
this.clip = value;
}
/**
* Set minimum and maximum values by data array
* @param a The data array
*/
public void autoScale(Array a) {
this.minValue = ArrayMath.min(a).doubleValue();
this.maxValue = ArrayMath.max(a).doubleValue();
}
/**
* Set minimum and maximum values by data array if minValue or maxValue is not set
* @param a The data array
*/
public void autoScaleNull(Array a) {
if (this.minValue == null)
this.minValue = ArrayMath.min(a).doubleValue();
if (this.maxValue == null)
this.maxValue = ArrayMath.max(a).doubleValue();
}
/**
* Check whether minimum and maximum values are set
* @return Boolean
*/
public boolean isScaled() {
return this.minValue != null && this.maxValue != null;
}
/**
* Normalize a value
* @param v The value
* @return Normalized value
*/
public Number apply(double v) {
double range = maxValue - minValue;
v = (v - minValue) / range;
if (clip) {
if (v < 0)
v = 0;
else if (v > 1)
v = 1;
}
return v;
}
/**
* Normalize the data array
* @param a The data array
* @return Normalized data array
*/
public Array apply(Array a) {
this.autoScaleNull(a);
Array r = Array.factory(DataType.DOUBLE, a.getShape());
IndexIterator iterA = a.getIndexIterator();
IndexIterator iterR = r.getIndexIterator();
double v, range = maxValue - minValue;
if (clip) {
while (iterA.hasNext()) {
v = iterA.getDoubleNext();
v = (v - minValue) / range;
if (v < 0)
v = 0;
else if (v > 1)
v = 1;
iterR.setDoubleNext(v);
}
} else {
while (iterA.hasNext()) {
v = iterA.getDoubleNext();
v = (v - minValue) / range;
iterR.setDoubleNext(v);
}
}
return r;
}
/**
* Inverse data value
* @param v The data value
* @return Inverse data value
*/
public double inverse(double v) {
return minValue + v * (maxValue - minValue);
}
/**
* Inverse data array
* @param a The data array
* @return Inverse data array
*/
public Array inverse(Array a) {
Array r = Array.factory(DataType.DOUBLE, a.getShape());
IndexIterator iterA = a.getIndexIterator();
IndexIterator iterR = r.getIndexIterator();
double v, range = maxValue - minValue;
while (iterA.hasNext()) {
v = iterA.getDoubleNext();
v = minValue + v * range;
iterR.setDoubleNext(v);
}
return r;
}
}

View File

@ -18,6 +18,7 @@ package org.meteoinfo.geometry.legend;
import org.meteoinfo.common.DataConvert;
import org.meteoinfo.common.colors.ColorMap;
import org.meteoinfo.common.colors.ColorUtil;
import org.meteoinfo.geometry.colors.Normalize;
import org.meteoinfo.geometry.shape.ShapeTypes;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
@ -55,6 +56,8 @@ package org.meteoinfo.geometry.legend;
private double maxValue;
private double undef;
private Map<Object, ColorBreak> uniqueValueMap;
private ColorMap colorMap;
private Normalize normalize;
// </editor-fold>
// <editor-fold desc="Constructor">
/**
@ -356,6 +359,25 @@ package org.meteoinfo.geometry.legend;
return legendBreaks.size();
}
/**
* Get valid legend breaks number
*
* @return The valid legend breaks number
*/
public int getValidBreakNum() {
if (this.hasNoData) {
int n = 0;
for (ColorBreak aCB : this.legendBreaks) {
if (!aCB.isNoData()) {
n += 1;
}
}
return n;
} else {
return getBreakNum();
}
}
/**
* Get visible legend breaks number
*
@ -387,6 +409,40 @@ package org.meteoinfo.geometry.legend;
return n;
}
/**
* Get color map
* @return Color map
*/
public ColorMap getColorMap() {
return this.colorMap;
}
/**
* Set color map
* @param value Color map
*/
public void setColorMap(ColorMap value) {
this.colorMap = value;
}
/**
* Get normalize
* @return Normalize
*/
public Normalize getNormalize() {
return this.normalize;
}
/**
* Set normalize
* @param value Normalize
*/
public void setNormalize(Normalize value) {
this.normalize = value;
this.minValue = normalize.getMinValue();
this.maxValue = normalize.getMaxValue();
}
// </editor-fold>
// <editor-fold desc="Methods">
/**

View File

@ -82,8 +82,8 @@
<orderEntry type="module" module-name="meteoinfo-dataframe" />
<orderEntry type="library" name="Maven: edu.ucar:netcdfAll:5.4.1" level="project" />
<orderEntry type="library" name="Maven: com.github.albfernandez:juniversalchardet:2.4.0" level="project" />
<orderEntry type="library" name="Maven: com.formdev:flatlaf:2.0-rc1" level="project" />
<orderEntry type="library" name="Maven: com.formdev:flatlaf-extras:2.0-rc1" level="project" />
<orderEntry type="library" name="Maven: com.formdev:flatlaf:2.0" level="project" />
<orderEntry type="library" name="Maven: com.formdev:flatlaf-extras:2.0" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: com.formdev:svgSalamander:1.1.3" level="project" />
<orderEntry type="library" name="Maven: com.itextpdf:itextpdf:5.5.13.2" level="project" />
<orderEntry type="module" module-name="meteoinfo-ui" />

View File

@ -1,32 +1,34 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<MeteoInfo File="milconfig.xml" Type="configurefile">
<Path OpenPath="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl">
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\toolbox\miml"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\toolbox\miml\model_persistence"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\map\projection"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\grads"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\satellite\calipso"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\traj"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\traj\TrajStat"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\satellite"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\satellite\modis"/>
<Path OpenPath="D:\Working\MIScript\Jython\mis\plot_types">
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d_earth"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\map"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\scatter"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\plot"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\chart\latex"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\chart"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\common_math\stats"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\common_math"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\chart\legend"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\array"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\satellite"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\map"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\contour"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types"/>
</Path>
<File>
<OpenedFiles>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d_earth\streamslice_pitch.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\volumeplot_perspective.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\volumeplot_1.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\satellite\OMPS-NPP_LP-L2_2.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\scatter\scatterm_1.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\imshow.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\imshow_normalize.py"/>
</OpenedFiles>
<RecentFiles>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d_earth\streamslice_pitch.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\volumeplot_perspective.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\volumeplot_1.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\satellite\OMPS-NPP_LP-L2_2.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\scatter\scatterm_1.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\imshow.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\imshow_normalize.py"/>
</RecentFiles>
</File>
<Font>
@ -34,5 +36,5 @@
</Font>
<LookFeel DockWindowDecorated="true" LafDecorated="true" Name="FlatDarkLaf"/>
<Figure DoubleBuffering="true"/>
<Startup MainFormLocation="-7,0" MainFormSize="1398,815"/>
<Startup MainFormLocation="-7,-7" MainFormSize="1293,685"/>
</MeteoInfo>

View File

@ -8,9 +8,11 @@ from ._figure import Figure
from ._glfigure import GLFigure
from .patches import *
from .lines import *
from .colors import *
__all__ = ['Figure','GLFigure','Axes','PolarAxes','MapAxes','Axes3D','Axes3DGL']
__all__ += miplot.__all__
__all__ += patches.__all__
__all__ += lines.__all__
__all__ += lines.__all__
__all__ += colors.__all__

View File

@ -17,6 +17,7 @@ from org.meteoinfo.geometry.legend import BarBreak, PolygonBreak, PolylineBreak,
PointBreak, LineStyles, PointStyle, LegendScheme, LegendType
from org.meteoinfo.geometry.shape import ShapeTypes
from org.meteoinfo.geometry.graphic import Graphic, GraphicCollection
from org.meteoinfo.geometry.colors import ExtendType
from org.meteoinfo.common import MIMath, Extent
from org.meteoinfo.geo.layer import MapLayer
@ -32,6 +33,7 @@ import mipylib.numeric as np
from mipylib.numeric.core import DimArray, NDArray
from mipylib.geolib.milayer import MILayer, MIXYListData
import plotutil
import colors
import mipylib.miutil as miutil
__all__ = ['Axes','PolarAxes']
@ -2114,12 +2116,6 @@ class Axes(object):
if isinstance(a, DimArray):
y = a.dimvalue(0)
x = a.dimvalue(1)
# if args[0].islondim(1):
# xaxistype = 'lon'
# elif args[0].islatdim(1):
# xaxistype = 'lat'
# elif args[0].istimedim(1):
# xaxistype = 'time'
else:
x = np.arange(a.shape[1])
y = np.arange(a.shape[0])
@ -2129,21 +2125,27 @@ class Axes(object):
y = args[1]
a = args[2]
args = args[3:]
vmin = kwargs.pop('vmin', a.min())
vmax = kwargs.pop('vmax', a.max())
if ls is None:
if len(args) > 0:
level_arg = args[0]
if isinstance(level_arg, int):
cn = level_arg
ls = LegendManage.createLegendScheme(a.min(), a.max(), cn, cmap)
ls = LegendManage.createLegendScheme(vmin, vmax, cn, cmap)
else:
if isinstance(level_arg, NDArray):
level_arg = level_arg.aslist()
ls = LegendManage.createLegendScheme(a.min(), a.max(), level_arg, cmap)
ls = LegendManage.createLegendScheme(vmin, vmax, level_arg, cmap)
else:
ls = LegendManage.createLegendScheme(a.min(), a.max(), cmap)
ls = LegendManage.createLegendScheme(vmin, vmax, cmap)
ls = ls.convertTo(ShapeTypes.POLYLINE)
plotutil.setlegendscheme(ls, **kwargs)
# norm = kwargs.pop('norm', colors.Normalize(vmin, vmax))
# ls.setNormalize(norm._norm)
# ls.setColorMap(cmap)
smooth = kwargs.pop('smooth', True)
if x.ndim == 2 and y.ndim == 2:
griddata_props = kwargs.pop('griddata_props', dict(method='idw', pointnum=5, convexhull=True))
@ -2246,12 +2248,6 @@ class Axes(object):
if isinstance(a, DimArray):
y = a.dimvalue(0)
x = a.dimvalue(1)
# if args[0].islondim(1):
# xaxistype = 'lon'
# elif args[0].islatdim(1):
# xaxistype = 'lat'
# elif args[0].istimedim(1):
# xaxistype = 'time'
else:
x = np.arange(a.shape[1])
y = np.arange(a.shape[0])
@ -2260,24 +2256,29 @@ class Axes(object):
x = args[0]
y = args[1]
a = args[2]
#gdata = np.asgriddata(a, x, y, fill_value)
args = args[3:]
vmin = kwargs.pop('vmin', a.min())
vmax = kwargs.pop('vmax', a.max())
if ls is None:
if len(args) > 0:
level_arg = args[0]
if isinstance(level_arg, int):
cn = level_arg
ls = LegendManage.createLegendScheme(a.min(), a.max(), cn, cmap)
ls = LegendManage.createLegendScheme(vmin, vmax, cn, cmap)
else:
if isinstance(level_arg, NDArray):
level_arg = level_arg.aslist()
ls = LegendManage.createLegendScheme(a.min(), a.max(), level_arg, cmap)
ls = LegendManage.createLegendScheme(vmin, vmax, level_arg, cmap)
else:
ls = LegendManage.createLegendScheme(a.min(), a.max(), cmap)
ls = LegendManage.createLegendScheme(vmin, vmax, cmap)
ls = ls.convertTo(ShapeTypes.POLYGON)
if not kwargs.has_key('edgecolor'):
kwargs['edgecolor'] = None
plotutil.setlegendscheme(ls, **kwargs)
# norm = kwargs.pop('norm', colors.Normalize(vmin, vmax))
# ls.setNormalize(norm._norm)
# ls.setColorMap(cmap)
smooth = kwargs.pop('smooth', True)
if x.ndim == 2 and y.ndim == 2:
griddata_props = kwargs.pop('griddata_props', dict(method='idw', pointnum=5, convexhull=True))
@ -2333,13 +2334,6 @@ class Axes(object):
isrgb = True
else:
gdata = np.asgridarray(X)
# if isinstance(X, DimArray):
# if X.islondim(1):
# xaxistype = 'lon'
# elif X.islatdim(1):
# xaxistype = 'lat'
# elif X.istimedim(1):
# xaxistype = 'time'
args = args[1:]
extent = kwargs.pop('extent', extent)
@ -2359,6 +2353,8 @@ class Axes(object):
else:
ls = kwargs.pop('symbolspec', None)
if ls is None:
vmin = kwargs.pop('vmin', gdata.min())
vmax = kwargs.pop('vmax', gdata.max())
if len(args) > 0:
level_arg = args[0]
if isinstance(level_arg, int):
@ -2369,11 +2365,14 @@ class Axes(object):
level_arg = level_arg.aslist()
ls = LegendManage.createImageLegend(gdata, level_arg, cmap)
else:
ls = plotutil.getlegendscheme(args, gdata.min(), gdata.max(), **kwargs)
ls = plotutil.getlegendscheme(args, vmin, vmax, **kwargs)
norm = kwargs.pop('norm', colors.Normalize(vmin, vmax))
ls.setNormalize(norm._norm)
ls.setColorMap(cmap)
ls = ls.convertTo(ShapeTypes.IMAGE)
plotutil.setlegendscheme(ls, **kwargs)
igraphic = GraphicFactory.createImage(gdata, ls, extent)
interpolation = kwargs.pop('interpolation', None)
if not interpolation is None:
igraphic.getShape().setInterpolation(interpolation)
@ -3517,6 +3516,8 @@ class Axes(object):
for lb in args[0]:
if isinstance(lb, Graphic):
lbs.append(lb.getLegend().clone())
elif isinstance(lb, MILayer):
lbs.extend(lb.legend().getLegendBreaks())
else:
lbs.append(lb)
if len(args) == 2:
@ -3744,6 +3745,8 @@ class Axes(object):
legend.setPlotOrientation(PlotOrientation.VERTICAL)
legend.setPosition(LegendPosition.RIGHT_OUTSIDE)
legend.setDrawNeatLine(False)
extend = kwargs.pop('extend', 'neither')
legend.setExtendType(extend)
extendrect = kwargs.pop('extendrect', True)
legend.setExtendRect(extendrect)
extendfrac = kwargs.pop('extendfrac', None)
@ -3802,6 +3805,8 @@ class Axes(object):
edgesize = kwargs.pop('edgesize')
legend.setNeatLineSize(edgesize)
return legend
###############################################
class PolarAxes(Axes):

View File

@ -0,0 +1,171 @@
from org.meteoinfo.geometry.colors import Normalize as JNormalize
from org.meteoinfo.geometry.colors import LogNorm as JLogNorm
from org.meteoinfo.geometry.colors import BoundaryNorm as JBoundaryNorm
from org.meteoinfo.geometry.colors import ExtendType
from org.meteoinfo.ndarray import Array
import mipylib.numeric as np
__all__ = ['Normalize','LogNorm','BoundaryNorm']
class Normalize(object):
"""
A class which, when called, linearly normalizes data into the
``[0.0, 1.0]`` interval.
"""
def __init__(self, vmin=None, vmax=None, clip=False):
"""
Parameters
----------
vmin, vmax : float or None
If *vmin* and/or *vmax* is not given, they are initialized from the
minimum and maximum value, respectively, of the first input
processed; i.e., ``__call__(A)`` calls ``autoscale_None(A)``.
clip : bool, default: False
If ``True`` values falling outside the range ``[vmin, vmax]``,
are mapped to 0 or 1, whichever is closer, and masked values are
set to 1. If ``False`` masked values remain masked.
Clipping silently defeats the purpose of setting the over, under,
and masked colors in a colormap, so it is likely to lead to
surprises; therefore the default is ``clip=False``.
Notes
-----
Returns 0 if ``vmin == vmax``.
"""
self._norm = JNormalize(vmin, vmax, clip)
@property
def vmin(self):
return self._norm.getMinValue()
@vmin.setter
def vmin(self, value):
if value != self._norm.getMinValue():
self._norm.setMinValue(value)
@property
def vmax(self):
return self._norm.getMaxValue()
@vmax.setter
def vmax(self, value):
if value != self._norm.getMaxValue():
self._norm.setMaxValue(value)
@property
def clip(self):
return self._norm.getClip()
@clip.setter
def clip(self, value):
if value != self._norm.getClip():
self._norm.setClip(value)
def __call__(self, value, clip=None):
"""
Normalize *value* data in the ``[vmin, vmax]`` interval into the
``[0.0, 1.0]`` interval and return it.
Parameters
----------
value
Data to normalize.
clip : bool
If ``None``, defaults to ``self.clip`` (which defaults to
``False``).
Notes
-----
If not already initialized, ``self.vmin`` and ``self.vmax`` are
initialized using ``self.autoscale_None(value)``.
"""
if not clip is None:
self._norm.setClip(clip)
if isinstance(value, (list, tuple)):
value = np.array(value)
r = self._norm.apply(value._array)
if isinstance(r, Array):
return np.array(r)
else:
return r
def inverse(self, value):
if isinstance(value, (list, tuple)):
value = np.array(value)
r = self._norm.inverse(value._array)
if isinstance(r, Array):
return np.array(r)
else:
return r
class LogNorm(Normalize):
"""Normalize a given value to the 0-1 range on a log scale."""
def __init__(self, vmin=None, vmax=None, clip=False):
"""
Parameters
----------
vmin, vmax : float or None
If *vmin* and/or *vmax* is not given, they are initialized from the
minimum and maximum value, respectively, of the first input
processed; i.e., ``__call__(A)`` calls ``autoscale_None(A)``.
clip : bool, default: False
If ``True`` values falling outside the range ``[vmin, vmax]``,
are mapped to 0 or 1, whichever is closer, and masked values are
set to 1. If ``False`` masked values remain masked.
Clipping silently defeats the purpose of setting the over, under,
and masked colors in a colormap, so it is likely to lead to
surprises; therefore the default is ``clip=False``.
Notes
-----
Returns 0 if ``vmin == vmax``.
"""
self._norm = JLogNorm(vmin, vmax, clip)
class BoundaryNorm(Normalize):
"""
Generate a colormap index based on discrete intervals.
Unlike `Normalize` or `LogNorm`, `BoundaryNorm` maps values to integers
instead of to the interval 0-1.
Mapping to the 0-1 interval could have been done via piece-wise linear
interpolation, but using integers seems simpler, and reduces the number of
conversions back and forth between integer and floating point.
"""
def __init__(self, boundaries, ncolors, clip=False, extend='neither'):
"""
Parameters
----------
boundaries : array-like
Monotonically increasing sequence of at least 2 boundaries.
ncolors : int
Number of colors in the colormap to be used.
clip : bool, optional
If clip is ``True``, out of range values are mapped to 0 if they
are below ``boundaries[0]`` or mapped to ``ncolors - 1`` if they
are above ``boundaries[-1]``.
If clip is ``False``, out of range values are mapped to -1 if
they are below ``boundaries[0]`` or mapped to *ncolors* if they are
above ``boundaries[-1]``.
extend : {'neither', 'both', 'min', 'max'}, default: 'neither'
Extend the number of bins to include one or both of the
regions beyond the boundaries.
Returns
-------
int16 scalar or array
Notes
-----
*boundaries* defines the edges of bins, and data falling within a bin
is mapped to the color with the same index.
If the number of bins, including any extensions, is less than
*ncolors*, the color index is chosen by linear interpolation, mapping
the ``[0, nbins - 1]`` range onto the ``[0, ncolors - 1]`` range.
"""
super(BoundaryNorm, self).__init__(vmin=boundaries[0], vmax=boundaries[-1], clip=clip)
if isinstance(boundaries, (list, tuple)):
boundaries = np.array(boundaries)
extend = ExtendType.valueOf(extend.upper())
self._norm = JBoundaryNorm(boundaries._array, ncolors, extend)

View File

@ -2096,8 +2096,9 @@ def colorbar(mappable=None, **kwargs):
cax = kwargs.pop('cax', None)
if cax is None:
cax = g_axes
cax.colorbar(mappable, **kwargs)
cb = cax.colorbar(mappable, **kwargs)
draw_if_interactive()
return cb
# def set(obj, **kwargs):
# '''

View File

@ -73,8 +73,8 @@
<orderEntry type="module" module-name="meteoinfo-dataframe" />
<orderEntry type="library" name="Maven: edu.ucar:netcdfAll:5.4.1" level="project" />
<orderEntry type="library" name="Maven: com.github.albfernandez:juniversalchardet:2.4.0" level="project" />
<orderEntry type="library" name="Maven: com.formdev:flatlaf:2.0-rc1" level="project" />
<orderEntry type="library" name="Maven: com.formdev:flatlaf-extras:2.0-rc1" level="project" />
<orderEntry type="library" name="Maven: com.formdev:flatlaf:2.0" level="project" />
<orderEntry type="library" name="Maven: com.formdev:flatlaf-extras:2.0" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: com.formdev:svgSalamander:1.1.3" level="project" />
<orderEntry type="library" name="Maven: com.itextpdf:itextpdf:5.5.13.2" level="project" />
<orderEntry type="module" module-name="meteoinfo-ui" />

View File

@ -2263,7 +2263,7 @@ public class ArrayUtil {
else if (idx == -(a.getSize() + 1))
idx = (int)a.getSize();
else {
idx = -idx - 2;
idx = -idx - 1;
}
}