Javafx and Swing DashBoard("Kenya Terror Attacks 1992 to 2014")
Long since i posted a javafx data viz project,i have been getting familiarized with javafx in IOT,my device of choice is the Raspberry PI.I will be posting my javafx IOT projects in the same blog spot no need for another blog since everything here is done in java only.
As any dataviz post the data can be found here,Global Terrorism Database has data for Kenya from 1992 to 2014,had to filter only incidents from Kenya.
The columns that i used are date,lat,lon,city,weapon type,kill,wounded.
The Visuals
the map WorldWindJava library Swing
the rest are Javafx nodes
Setting up the Map
WorldWindowGLJPanel wwd =new WorldWindowGLJPanel ();
RenderableLayer rl = new RenderableLayer();
BasicModel basicModel=new BasicModel();
EarthFlat ef=new EarthFlat();
BasicView bsv=new BasicView();
bsv.setGlobe(ef);
wwd.setModel(basicModel);
wwd.getModel().setGlobe(ef);
wwd.getModel().getLayers().removeAll();
wwd.getModel().getLayers().add(rl);
//zoom to area with points
Sector bounds = Sector.boundingSector(pos);
BasicOrbitView fov = (BasicOrbitView) wwd.getView();
fov.setCenterPosition(Position.fromDegrees(bounds.getCentroid().getLatitude().degrees, bounds.getCentroid().getLongitude().degrees));
double radii = wwd.getModel().getExtent().getRadius();
double viewRange = Math.sqrt(Math.pow(bounds.getMaxLatitude().degrees- bounds.getMinLatitude().degrees,3)+Math.pow(bounds.getMaxLongitude().degrees-bounds.getMinLongitude().degrees, 3));
double altitude = radii * Math.sin(Math.toRadians(viewRange * 0.5));
wwd.setPreferredSize(new Dimension(800,650));
fov.setZoom(altitude);
Marker
int MAX_VAL=241;
int MAX_RADIUS=60000;
private SurfaceCircle addKills(String item[]){
double lat=Double.valueOf(item[0]);
double lon=Double.valueOf(item[1]);
double killed=Double.valueOf(item[2]);
LatLon latlon=new LatLon(Angle.fromDegreesLatitude(lat)),
Angle.fromDegreesLongitude(lon));
d=Math.sqrt(Math.pow(MAX_RADIUS,2) *killed /MAX_VAL);
kills+=Double.valueOf(item[2]);
Platform.runLater(() -> {
dead_txt.setText("Dead : "+kills);
});
double radius=d==0?1000:d;
SurfaceCircle sp=new SurfaceCircle(latlon,radius);
BasicShapeAttributes sb=new BasicShapeAttributes();
sb.setInteriorMaterial(Material.RED);
sb.setOutlineMaterial(Material.RED);
sb.setEnableAntialiasing(true);
sb.setOutlineOpacity(0.2);
sb.setInteriorOpacity(0.2);
sp.setAttributes(sb);
return sp;
}
Animate
private Timer animate() throws Exception{
javax.swing.Timer timer=new Timer(1, (ActionEvent e) -> {
if(i==lines.size()-1){
tm.stop();
i=0;
}
String s=lines.get(i);
String item[]=s.split(",");
SurfaceCircle attacks= addKills(item);
SurfaceCircle injuries= addInjuries(item);
rl.addRenderable(injuries);
rl.addRenderable(attacks);
rl.firePropertyChange(AVKey.LAYER, null, this);//redraw layer
Platform.runLater(() -> {
Label label=(Label) root.lookup("#"+item[4]);
label.setFont(Font.font("arial", 9));
label.setTextFill(Color.WHITE);
incidents_txt.setText("No of Incidents : "+i);
});
i++;
});
return timer;
My log listcell class
public class LogListCell extends ListCell<String>{
GridPane root;
Text date_txt;
Text weapon_txt;
Text kill_txt;
Text wound_txt;
Text city_txt;
LogListCell (){
root=new GridPane();
root.setAlignment(Pos.TOP_LEFT);
root.setHgap(5);
root.setVgap(5);
root.setId("gridPane");
date_txt=new Text("Date : ");
date_txt.setFill(Color.WHITE);
root.add(date_txt, 0, 0);
city_txt=new Text("City : ");
city_txt.setFill(Color.WHITE);
root.add(city_txt, 0, 1);
weapon_txt=new Text("Weapon : ");
weapon_txt.setFill(Color.WHITE);
root.add(weapon_txt, 0, 2);
kill_txt=new Text("Dead : ");
kill_txt.setFill(Color.RED);
root.add(kill_txt, 0, 3);
wound_txt=new Text("Injured : ");
wound_txt.setFill(Color.ORANGE);
root.add(wound_txt, 0, 4);
}
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if(!empty){
setGraphic(root);
String rry[]=item.split(",");
date_txt.setText("Date : "+rry[4]);
city_txt.setText("City : "+rry[3]);
weapon_txt.setText("Weapon : "+rry[6]);
kill_txt.setText("Dead : "+rry[2]);
wound_txt.setText("Injured : "+rry[5]);
}
}
}
private void onYearClicked(){
for(int year=1992;year<2015;year++){
Label label=new Label();
label.setId(String.valueOf(year));
label.setFont(Font.font("arial", 9));
label.setTextFill(Color.GREY);
label.setOnMouseClicked((MouseEvent event) -> {
label.setTextFill(Color.WHITE);
temp_data=lines.stream()
.filter(s->s.contains(label.getText()))
.collect(toList());
incidents+=temp_data.size();
incidents_txt.setText("No of Incidents : "+incidents);
list_view_data.addAll(temp_data);
list_view.setItems(list_view_data);
for(String s:temp_points){
String item[]=s.split(",");
SurfaceCircle attacks= addKills(item);
SurfaceCircle injuries=addInjuries(item);
rl.addRenderable(injuries);
rl.addRenderable(attacks);
rl.firePropertyChange(AVKey.LAYER, null, this);
}
});
label.setText(String.valueOf(year));
label.setLayoutX(y_axis);
label.setLayoutY(660);
y_axis+=30;
root.getChildren().add(label);
}
}
Since i want the dashboard to be interactive in any way,i wouldn't say that its a finished project and the data still has some columns i would like to add,and the list view isn't interactive yet.
Results
Video
As any dataviz post the data can be found here,Global Terrorism Database has data for Kenya from 1992 to 2014,had to filter only incidents from Kenya.
The columns that i used are date,lat,lon,city,weapon type,kill,wounded.
The Visuals
the map WorldWindJava library Swing
the rest are Javafx nodes
Setting up the Map
WorldWindowGLJPanel wwd =new WorldWindowGLJPanel ();
RenderableLayer rl = new RenderableLayer();
BasicModel basicModel=new BasicModel();
EarthFlat ef=new EarthFlat();
BasicView bsv=new BasicView();
bsv.setGlobe(ef);
wwd.setModel(basicModel);
wwd.getModel().setGlobe(ef);
wwd.getModel().getLayers().removeAll();
wwd.getModel().getLayers().add(rl);
//zoom to area with points
Sector bounds = Sector.boundingSector(pos);
BasicOrbitView fov = (BasicOrbitView) wwd.getView();
fov.setCenterPosition(Position.fromDegrees(bounds.getCentroid().getLatitude().degrees, bounds.getCentroid().getLongitude().degrees));
double radii = wwd.getModel().getExtent().getRadius();
double viewRange = Math.sqrt(Math.pow(bounds.getMaxLatitude().degrees- bounds.getMinLatitude().degrees,3)+Math.pow(bounds.getMaxLongitude().degrees-bounds.getMinLongitude().degrees, 3));
double altitude = radii * Math.sin(Math.toRadians(viewRange * 0.5));
wwd.setPreferredSize(new Dimension(800,650));
fov.setZoom(altitude);
Marker
int MAX_VAL=241;
int MAX_RADIUS=60000;
private SurfaceCircle addKills(String item[]){
double lat=Double.valueOf(item[0]);
double lon=Double.valueOf(item[1]);
double killed=Double.valueOf(item[2]);
LatLon latlon=new LatLon(Angle.fromDegreesLatitude(lat)),
Angle.fromDegreesLongitude(lon));
d=Math.sqrt(Math.pow(MAX_RADIUS,2) *killed /MAX_VAL);
kills+=Double.valueOf(item[2]);
Platform.runLater(() -> {
dead_txt.setText("Dead : "+kills);
});
double radius=d==0?1000:d;
SurfaceCircle sp=new SurfaceCircle(latlon,radius);
BasicShapeAttributes sb=new BasicShapeAttributes();
sb.setInteriorMaterial(Material.RED);
sb.setOutlineMaterial(Material.RED);
sb.setEnableAntialiasing(true);
sb.setOutlineOpacity(0.2);
sb.setInteriorOpacity(0.2);
sp.setAttributes(sb);
return sp;
}
Animate
private Timer animate() throws Exception{
javax.swing.Timer timer=new Timer(1, (ActionEvent e) -> {
if(i==lines.size()-1){
tm.stop();
i=0;
}
String s=lines.get(i);
String item[]=s.split(",");
SurfaceCircle attacks= addKills(item);
SurfaceCircle injuries= addInjuries(item);
rl.addRenderable(injuries);
rl.addRenderable(attacks);
rl.firePropertyChange(AVKey.LAYER, null, this);//redraw layer
Platform.runLater(() -> {
Label label=(Label) root.lookup("#"+item[4]);
label.setFont(Font.font("arial", 9));
label.setTextFill(Color.WHITE);
incidents_txt.setText("No of Incidents : "+i);
});
i++;
});
return timer;
My log listcell class
public class LogListCell extends ListCell<String>{
GridPane root;
Text date_txt;
Text weapon_txt;
Text kill_txt;
Text wound_txt;
Text city_txt;
LogListCell (){
root=new GridPane();
root.setAlignment(Pos.TOP_LEFT);
root.setHgap(5);
root.setVgap(5);
root.setId("gridPane");
date_txt=new Text("Date : ");
date_txt.setFill(Color.WHITE);
root.add(date_txt, 0, 0);
city_txt=new Text("City : ");
city_txt.setFill(Color.WHITE);
root.add(city_txt, 0, 1);
weapon_txt=new Text("Weapon : ");
weapon_txt.setFill(Color.WHITE);
root.add(weapon_txt, 0, 2);
kill_txt=new Text("Dead : ");
kill_txt.setFill(Color.RED);
root.add(kill_txt, 0, 3);
wound_txt=new Text("Injured : ");
wound_txt.setFill(Color.ORANGE);
root.add(wound_txt, 0, 4);
}
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if(!empty){
setGraphic(root);
String rry[]=item.split(",");
date_txt.setText("Date : "+rry[4]);
city_txt.setText("City : "+rry[3]);
weapon_txt.setText("Weapon : "+rry[6]);
kill_txt.setText("Dead : "+rry[2]);
wound_txt.setText("Injured : "+rry[5]);
}
}
}
setting custom cell to the listview
list_view.setCellFactory((ListView<String> list1) -> new LogListCell ());
Year Labels
for(int year=1992;year<2015;year++){
Label label=new Label();
label.setId(String.valueOf(year));
label.setFont(Font.font("arial", 9));
label.setTextFill(Color.GREY);
label.setOnMouseClicked((MouseEvent event) -> {
label.setTextFill(Color.WHITE);
temp_data=lines.stream()
.filter(s->s.contains(label.getText()))
.collect(toList());
incidents+=temp_data.size();
incidents_txt.setText("No of Incidents : "+incidents);
list_view_data.addAll(temp_data);
list_view.setItems(list_view_data);
for(String s:temp_points){
String item[]=s.split(",");
SurfaceCircle attacks= addKills(item);
SurfaceCircle injuries=addInjuries(item);
rl.addRenderable(injuries);
rl.addRenderable(attacks);
rl.firePropertyChange(AVKey.LAYER, null, this);
}
});
label.setText(String.valueOf(year));
label.setLayoutX(y_axis);
label.setLayoutY(660);
y_axis+=30;
root.getChildren().add(label);
}
}
Since i want the dashboard to be interactive in any way,i wouldn't say that its a finished project and the data still has some columns i would like to add,and the list view isn't interactive yet.
Results
1998 bomb blast |
2010,2011,2012,2013,2014 attacks |
2014 attacks |
1992_2014 attacks |
Hey!
ReplyDeleteGreat work you doing there.