Skip to content

Commit ccbe088

Browse files
authored
Merge pull request #126 from kdbinsidebrains/charting
charting
2 parents 145addd + b89b6cb commit ccbe088

20 files changed

+882
-150
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
# KdbInsideBrains Changelog
22

3+
## 6.2.0
4+
5+
### Added
6+
7+
- Bar/Area charting use transparent colours to view more details
8+
- New Legend charting tool has been added to display current values on the chart.
9+
10+
### Fixed
11+
12+
- Charting timezone issue in Table tool fixed
13+
314
## 6.1.1
415

516
### Changed

src/main/java/icons/KdbIcons.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ public static final class Chart {
5959
public static final @NotNull Icon ToolCrosshair = load("/org/kdb/inside/brains/icons/chart/tool_crosshair.svg");
6060
public static final @NotNull Icon ToolPoints = load("/org/kdb/inside/brains/icons/chart/tool_points.svg");
6161
public static final @NotNull Icon ToolMeasure = load("/org/kdb/inside/brains/icons/chart/tool_measure.svg");
62+
public static final @NotNull Icon ToolLegend = load("/org/kdb/inside/brains/icons/chart/tool_legend.svg");
6263

6364
public static final @NotNull Icon Templates = load("/org/kdb/inside/brains/icons/chart/template.svg");
6465
}

src/main/java/org/kdb/inside/brains/view/KdbOutputFormatter.java

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,19 @@
1717
import java.util.function.Function;
1818

1919
public final class KdbOutputFormatter {
20+
public static final String NULL_INT_TEXT = "0Ni";
21+
public static final String NULL_SHORT_TEXT = "0Nh";
22+
public static final String NULL_FLOAT_TEXT = "0Ne";
23+
public static final String NULL_UUID_TEXT = "0Ng";
24+
public static final String NULL_DATE_TEXT = "0Nd";
25+
public static final String NULL_TIME_TEXT = "0Nt";
26+
public static final String NULL_MONTH_TEXT = "0Nm";
27+
public static final String NULL_MINUTE_TEXT = "0Nu";
28+
public static final String NULL_SECOND_TEXT = "0Nv";
29+
public static final String NULL_DATETIME_TEXT = "0Nz";
30+
public static final String NULL_TIMESPAN_TEXT = "0Nn";
31+
public static final String NULL_TIMESTAMP_TEXT = "0Np";
32+
2033
private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
2134

2235
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy.MM.dd");
@@ -31,6 +44,7 @@ public final class KdbOutputFormatter {
3144
private static final DecimalFormat[][] DECIMAL_SEPARATOR = new DecimalFormat[RoundingMode.values().length][NumericalOptions.MAX_DECIMAL_PRECISION + 1];
3245
private static final DecimalFormat[][] DECIMAL_SCIENTIFIC = new DecimalFormat[RoundingMode.values().length][NumericalOptions.MAX_DECIMAL_PRECISION + 1];
3346

47+
3448
private static KdbOutputFormatter defaultInstance;
3549

3650
static {
@@ -392,7 +406,7 @@ public String formatBytes(byte[] v) {
392406

393407
@NotNull
394408
public String formatShort(short v) {
395-
return isNull(v) ? "0Nh" : shortToStr(v) + "h";
409+
return isNull(v) ? NULL_SHORT_TEXT : shortToStr(v) + "h";
396410
}
397411

398412
@NotNull
@@ -414,7 +428,7 @@ public String formatShorts(short[] k) {
414428

415429
@NotNull
416430
public String formatInt(int v) {
417-
return isNull(v) ? "0Ni" : intToStr(v) + "i";
431+
return isNull(v) ? NULL_INT_TEXT : intToStr(v) + "i";
418432
}
419433

420434
@NotNull
@@ -458,7 +472,7 @@ public String formatLongs(long[] v) {
458472

459473
@NotNull
460474
public String formatFloat(float v) {
461-
return isNull(v) ? "0Ne" : floatToStr(v) + "e";
475+
return isNull(v) ? NULL_FLOAT_TEXT : floatToStr(v) + "e";
462476
}
463477

464478
@NotNull
@@ -524,7 +538,7 @@ public String formatDoubles(double[] v) {
524538
@NotNull
525539
public String formatTimestamp(Timestamp v) {
526540
if (isNull(v)) {
527-
return "0Np";
541+
return NULL_TIMESTAMP_TEXT;
528542
}
529543

530544
StringBuilder b = new StringBuilder(10);
@@ -538,42 +552,42 @@ public String formatTimestamp(Timestamp v) {
538552

539553
@NotNull
540554
public String formatUUID(UUID v) {
541-
return isNull(v) ? "0Ng" : String.valueOf(v);
555+
return isNull(v) ? NULL_UUID_TEXT : String.valueOf(v);
542556
}
543557

544558
@NotNull
545559
public String formatDate(Date v) {
546-
return isNull(v) ? "0Nd" : DATE_FORMAT.format(v);
560+
return isNull(v) ? NULL_DATE_TEXT : DATE_FORMAT.format(v);
547561
}
548562

549563
@NotNull
550564
public String formatTime(Time v) {
551-
return isNull(v) ? "0Nt" : TIME_FORMAT.format(v);
565+
return isNull(v) ? NULL_TIME_TEXT : TIME_FORMAT.format(v);
552566
}
553567

554568
@NotNull
555569
public String formatDatetime(java.util.Date v) {
556-
return isNull(v) ? "0Nz" : DATETIME_FORMAT.format(v);
570+
return isNull(v) ? NULL_DATETIME_TEXT : DATETIME_FORMAT.format(v);
557571
}
558572

559573
@NotNull
560574
public String formatTimespan(c.Timespan v) {
561-
return isNull(v) ? "0Nn" : String.valueOf(v);
575+
return isNull(v) ? NULL_TIMESPAN_TEXT : String.valueOf(v);
562576
}
563577

564578
@NotNull
565579
public String formatMonth(c.Month v) {
566-
return isNull(v) ? "0Nm" : String.valueOf(v);
580+
return isNull(v) ? NULL_MONTH_TEXT : String.valueOf(v);
567581
}
568582

569583
@NotNull
570584
public String formatMinute(c.Minute v) {
571-
return isNull(v) ? "0Nu" : String.valueOf(v);
585+
return isNull(v) ? NULL_MINUTE_TEXT : String.valueOf(v);
572586
}
573587

574588
@NotNull
575589
public String formatSecond(c.Second v) {
576-
return isNull(v) ? "0Nv" : String.valueOf(v);
590+
return isNull(v) ? NULL_SECOND_TEXT : String.valueOf(v);
577591
}
578592

579593
@NotNull
@@ -722,7 +736,7 @@ private boolean isNull(Object v) {
722736

723737
private String getKdbTypeName(Class<?> aClass) {
724738
final KdbType kdbType = KdbType.typeOf(aClass);
725-
return kdbType == null || kdbType == KdbType.ANY ? null : kdbType.getTypeName();
739+
return kdbType == KdbType.ANY ? null : kdbType.getTypeName();
726740
}
727741

728742
private boolean isScientificNotation(double s) {
Lines changed: 5 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package org.kdb.inside.brains.view.chart;
22

33
import com.intellij.ui.JBColor;
4-
import com.intellij.util.ui.ColorIcon;
54

65
import java.awt.*;
76
import java.util.stream.Stream;
@@ -10,7 +9,7 @@ public final class ChartColors {
109
private ChartColors() {
1110
}
1211

13-
private static final String colorsMatrixChatGpt = """
12+
private static final String COLOR_MATRIX_CHART = """
1413
#FF5733 #33FF57 #3357FF #FF33A6 #A633FF #33FFF6
1514
#F6FF33 #5733FF #33A6FF #A6FF33 #57FF33 #FF6F33
1615
#6FFF33 #33FF6F #336FFF #6F33FF #FF336F #FF8C33
@@ -22,21 +21,14 @@ private ChartColors() {
2221
#33CCFF #3399FF #3366FF #3333FF #6633FF #9933FF
2322
#CC33FF #FF33FF #FF33CC #FF3399 #FF3366 #FF3333
2423
""";
24+
2525
public static final Color[] DEFAULT_COLORS =
26-
Stream.of(colorsMatrixChatGpt.split("\\s+"))
26+
Stream.of(COLOR_MATRIX_CHART.split("\\s+"))
2727
.filter(s -> !s.isEmpty())
2828
.map(s -> s.replace("#", "0x").trim())
2929
.map(Color::decode)
3030
.toArray(Color[]::new);
3131

32-
private static final String colorsMatrixChatOriginal = """
33-
#3366cc #dc3912 #ff9900 #109618 #990099 #0099c6 #dd4477
34-
#66aa00 #b82e2e #316395 #994499 #22aa99 #aaaa11 #6633cc
35-
#e67300 #8b0707 #651067 #329262 #5574a6 #3b3eac #b77322
36-
#16d620 #b91383 #f4359e #9c5935 #a9c413 #2a778d #668d1c
37-
#bea413 #0c5922 #743411
38-
""";
39-
4032
public static final JBColor POSITIVE = new JBColor(Color.decode("0x1c6b3b"), Color.decode("0x49754d"));
4133
public static final JBColor NEGATIVE = new JBColor(Color.decode("0xea0d3f"), Color.decode("0xe3415d"));
4234

@@ -49,57 +41,12 @@ private ChartColors() {
4941
transparent(Color.decode("0xe3415d"), 40)
5042
);
5143

52-
private static Color transparent(Color c, int alpha) {
44+
public static Color transparent(Color c, int alpha) {
5345
return new Color(c.getRed(), c.getGreen(), c.getBlue(), alpha);
5446
}
5547

56-
// Cycled color wheel by index
48+
// Cycled colour wheel by index
5749
public static Color getDefaultColor(int index) {
5850
return DEFAULT_COLORS[index - (DEFAULT_COLORS.length * (index / DEFAULT_COLORS.length))];
5951
}
60-
61-
public static ColorIcon createIcon(Color color) {
62-
if (color == null) {
63-
return null;
64-
}
65-
return new ColorIcon(25, 15, 20, 10, color, true);
66-
}
67-
68-
69-
/*
70-
private static class ColorTableCellEditor extends AbstractCellEditor implements TableCellEditor, TableCellRenderer {
71-
private final DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
72-
private Color editingColor;
73-
74-
@Override
75-
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
76-
final JLabel label = (JLabel) renderer.getTableCellRendererComponent(table, null, isSelected, hasFocus, row, column);
77-
label.setIcon(ChartColors.createIcon((Color) value));
78-
return label;
79-
}
80-
81-
@Override
82-
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
83-
final JLabel res = (JLabel) getTableCellRendererComponent(table, value, true, false, row, column);
84-
85-
editingColor = (Color) value;
86-
ApplicationManager.getApplication().invokeLater(() -> {
87-
final Color c = ColorChooser.chooseColor(table, IdeBundle.message("dialog.title.choose.color"), editingColor, true);
88-
if (c == null) {
89-
cancelCellEditing();
90-
} else {
91-
editingColor = c;
92-
stopCellEditing();
93-
}
94-
});
95-
return res;
96-
}
97-
98-
@Override
99-
public Object getCellEditorValue() {
100-
return editingColor;
101-
}
102-
}
103-
*/
104-
10552
}

src/main/java/org/kdb/inside/brains/view/chart/ChartDataProvider.java

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,22 @@
33
import kx.KxConnection;
44
import kx.c;
55
import org.jfree.data.time.*;
6-
import org.jfree.data.time.Month;
76
import org.kdb.inside.brains.KdbType;
87
import org.kdb.inside.brains.view.console.table.QTableModel;
98
import org.kdb.inside.brains.view.console.table.TableResult;
109

1110
import java.sql.Timestamp;
12-
import java.time.*;
11+
import java.time.Instant;
12+
import java.time.LocalDate;
13+
import java.time.LocalTime;
14+
import java.time.ZoneOffset;
1315
import java.time.temporal.ChronoUnit;
1416
import java.util.*;
1517
import java.util.stream.Stream;
1618

1719
public interface ChartDataProvider {
20+
Locale DEFAULT_LOCALE = Locale.getDefault();
21+
1822
LocalDate KDB_FIRST_DATE = LocalDate.of(2000, 1, 1);
1923

2024
static ChartDataProvider of(TableResult table) {
@@ -84,42 +88,37 @@ static Object createKdbTemporal(long millis, KdbType type) {
8488

8589
static Date createDate(Object value) {
8690
// SQL Date, Time, Timestamp is here
87-
Date res;
8891
if (value instanceof Date date) {
89-
res = date;
92+
return date;
9093
} else if (value instanceof c.Month month) {
9194
final long epochMilli = KDB_FIRST_DATE.plusMonths(month.i).atTime(LocalTime.MIDNIGHT).atZone(ZoneOffset.UTC).toInstant().toEpochMilli();
92-
res = new Date(epochMilli);
95+
return new Date(epochMilli);
9396
} else if (value instanceof c.Second v) {
94-
res = new Date(v.i * 1_000L);
97+
return new Date(v.i * 1_000L);
9598
} else if (value instanceof c.Minute v) {
96-
res = new Date(v.i * 60_000L);
99+
return new Date(v.i * 60_000L);
97100
} else if (value instanceof c.Timespan v) {
98-
res = new Date(v.j / 1_000_000L);
99-
} else {
100-
throw new IllegalArgumentException("Invalid value style: " + value.getClass());
101+
return new Date(v.j / 1_000_000L);
101102
}
102-
final ZonedDateTime f = Instant.ofEpochMilli(res.getTime()).atZone(ZoneId.systemDefault()).withZoneSameLocal(ZoneId.systemDefault());
103-
final ZonedDateTime t = f.withZoneSameInstant(ZoneOffset.UTC).withZoneSameLocal(ZoneId.systemDefault());
104-
return Date.from(t.toInstant());
103+
throw new IllegalArgumentException("Invalid value style: " + value.getClass());
105104
}
106105

107106
static RegularTimePeriod createPeriod(Object value) {
108107
if (value instanceof java.sql.Date date) {
109-
return new Day(date, KxConnection.UTC_TIMEZONE, Locale.getDefault());
108+
return new Day(date, KxConnection.UTC_TIMEZONE, DEFAULT_LOCALE);
110109
} else if (value instanceof java.sql.Time time) {
111-
return new Millisecond(time, KxConnection.UTC_TIMEZONE, Locale.getDefault());
110+
return new Millisecond(time, KxConnection.UTC_TIMEZONE, DEFAULT_LOCALE);
112111
} else if (value instanceof java.util.Date datetime) {
113-
return new Millisecond(datetime, KxConnection.UTC_TIMEZONE, Locale.getDefault());
112+
return new Millisecond(datetime, KxConnection.UTC_TIMEZONE, DEFAULT_LOCALE);
114113
} else if (value instanceof c.Month v) {
115114
final long epochMilli = KDB_FIRST_DATE.plusMonths(v.i).atTime(LocalTime.MIDNIGHT).toInstant(ZoneOffset.UTC).toEpochMilli();
116-
return new Month(new Date(epochMilli), KxConnection.UTC_TIMEZONE, Locale.getDefault());
115+
return new Month(new Date(epochMilli), KxConnection.UTC_TIMEZONE, DEFAULT_LOCALE);
117116
} else if (value instanceof c.Second v) {
118-
return new Second(new Date(v.i * 1_000L), KxConnection.UTC_TIMEZONE, Locale.getDefault());
117+
return new Second(new Date(v.i * 1_000L), KxConnection.UTC_TIMEZONE, DEFAULT_LOCALE);
119118
} else if (value instanceof c.Minute v) {
120-
return new Minute(new Date(v.i * 60_000L), KxConnection.UTC_TIMEZONE, Locale.getDefault());
119+
return new Minute(new Date(v.i * 60_000L), KxConnection.UTC_TIMEZONE, DEFAULT_LOCALE);
121120
} else if (value instanceof c.Timespan v) {
122-
return new Millisecond(new Date(v.j / 1_000_000L), KxConnection.UTC_TIMEZONE, Locale.getDefault());
121+
return new Millisecond(new Date(v.j / 1_000_000L), KxConnection.UTC_TIMEZONE, DEFAULT_LOCALE);
123122
}
124123
throw new IllegalArgumentException("Invalid value style: " + value.getClass());
125124
}

0 commit comments

Comments
 (0)