pax_global_header 0000666 0000000 0000000 00000000064 12657057427 0014531 g ustar 00root root 0000000 0000000 52 comment=6f1d3995960e5ce3e468b1e9e8cf202263c12ba7
elki-release0.7.1/ 0000775 0000000 0000000 00000000000 12657057427 0014023 5 ustar 00root root 0000000 0000000 elki-release0.7.1/.classpath 0000664 0000000 0000000 00000000744 12657057427 0016013 0 ustar 00root root 0000000 0000000
elki-release0.7.1/.gitignore 0000664 0000000 0000000 00000000077 12657057427 0016017 0 ustar 00root root 0000000 0000000 /target/
/local/
/**/target
/MiniGUI-saved-settings.txt
/**/*~
elki-release0.7.1/.project 0000664 0000000 0000000 00000001035 12657057427 0015471 0 ustar 00root root 0000000 0000000
elki-projectorg.eclipse.jdt.core.javabuilderorg.eclipse.m2e.core.maven2Builderorg.eclipse.m2e.core.maven2Natureorg.eclipse.jdt.core.javanature
elki-release0.7.1/.settings/ 0000775 0000000 0000000 00000000000 12657057427 0015741 5 ustar 00root root 0000000 0000000 elki-release0.7.1/.settings/org.eclipse.core.resources.prefs 0000664 0000000 0000000 00000000067 12657057427 0024157 0 ustar 00root root 0000000 0000000 eclipse.preferences.version=1
encoding/=UTF-8
elki-release0.7.1/.settings/org.eclipse.jdt.core.prefs 0000664 0000000 0000000 00000056443 12657057427 0022737 0 ustar 00root root 0000000 0000000 eclipse.preferences.version=1
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=0
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=0
org.eclipse.jdt.core.formatter.alignment_for_compact_if=0
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=0
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=0
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=0
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
org.eclipse.jdt.core.formatter.blank_lines_before_field=1
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
org.eclipse.jdt.core.formatter.comment.format_header=false
org.eclipse.jdt.core.formatter.comment.format_html=true
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
org.eclipse.jdt.core.formatter.comment.format_source_code=true
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
org.eclipse.jdt.core.formatter.comment.line_length=80
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
org.eclipse.jdt.core.formatter.compact_else_if=true
org.eclipse.jdt.core.formatter.continuation_indentation=2
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_empty_lines=false
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
org.eclipse.jdt.core.formatter.indentation.size=2
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
org.eclipse.jdt.core.formatter.lineSplit=80
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
org.eclipse.jdt.core.formatter.tabulation.char=space
org.eclipse.jdt.core.formatter.tabulation.size=2
org.eclipse.jdt.core.formatter.use_on_off_tags=false
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
elki-release0.7.1/.settings/org.eclipse.jdt.ui.prefs 0000664 0000000 0000000 00000013670 12657057427 0022417 0 ustar 00root root 0000000 0000000 eclipse.preferences.version=1
formatter_profile=_ELKI
formatter_settings_version=12
org.eclipse.jdt.ui.javadoc=false
org.eclipse.jdt.ui.text.custom_code_templates=/**\n * @return the ${bare_field_name}\n *//**\n * @param ${param} the ${bare_field_name} to set\n *//**\n * Constructor.\n *\n * ${tags}\n *//**\n * @author ${user}\n *\n * ${tags}\n *//**\n * \n *//**\n * ${tags}\n *//**\n * ${tags}\n * ${see_to_target}\n */${filecomment}\n${package_declaration}\n/*\n This file is part of ELKI\:\n Environment for Developing KDD-Applications Supported by Index-Structures\n\n Copyright (C) ${year}\n Ludwig-Maximilians-Universit\u00E4t M\u00FCnchen\n Lehr- und Forschungseinheit f\u00FCr Datenbanksysteme\n ELKI Development Team\n\n This program is free software\: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http\://www.gnu.org/licenses/>.\n */\n\n${typecomment}\n${type_declaration}\n\n\n\n// ${todo} Auto-generated catch block\nde.lmu.ifi.dbs.elki.logging.LoggingUtil.exception(${exception_var});// ${todo} Auto-generated method stub\n${body_statement}${body_statement}\n// ${todo} Auto-generated constructor stubreturn ${field};${field} \= ${param};
elki-release0.7.1/.settings/org.eclipse.m2e.core.prefs 0000664 0000000 0000000 00000000131 12657057427 0022620 0 ustar 00root root 0000000 0000000 activeProfiles=svg
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1
elki-release0.7.1/.travis.yml 0000664 0000000 0000000 00000000375 12657057427 0016141 0 ustar 00root root 0000000 0000000 language: java
install: mvn -Psvg,tutorial,svm -DskipTests=true -Dmaven.javadoc.skip=true -B -V clean install
script: mvn -Pcodecov -DskipTests=false -Dmaven.javadoc.skip=true -B -V test
before_install: pip install --user codecov
after_success: codecov
elki-release0.7.1/README.md 0000664 0000000 0000000 00000021433 12657057427 0015305 0 ustar 00root root 0000000 0000000 # ELKI
##### Environment for Developing KDD-Applications Supported by Index-Structures
[](http://dblp.uni-trier.de/rec/bibtex/journals/pvldb/SchubertKEZSZ15)
[](http://elki.dbs.ifi.lmu.de/wiki/License)
[](https://travis-ci.org/elki-project/elki)
## Quick Summary
ELKI is an open source (AGPLv3) data mining software written in Java. The focus of ELKI is research in algorithms, with an emphasis on unsupervised methods in cluster analysis and outlier detection.
In order to achieve high performance and scalability, ELKI offers many data index structures such as the R*-tree that can provide major performance gains.
ELKI is designed to be easy to extend for researchers and students in this domain, and welcomes contributions in particular of new methods.
ELKI aims at providing a large collection of highly parameterizable algorithms, in order to allow easy and fair evaluation and benchmarking of algorithms.
## Background
Data mining research leads to many algorithms for similar tasks. A fair and useful comparison of these algorithms is difficult due to several reasons:
* Implementations of comparison partners are not at hand.
* If implementations of different authors are provided, an evaluation in terms of efficiency is biased to evaluate the efforts of different authors in efficient programming instead of evaluating algorithmic merits.
On the other hand, efficient data management tools like index-structures can show considerable impact on data mining tasks and are therefore useful for a broad variety of algorithms.
In ELKI, data mining algorithms and data management tasks are separated and allow for an independent evaluation. This separation makes ELKI unique among data mining frameworks like Weka or Rapidminer and frameworks for index structures like GiST. At the same time, ELKI is open to arbitrary data types, distance or similarity measures, or file formats. The fundamental approach is the independence of file parsers or database connections, data types, distances, distance functions, and data mining algorithms. Helper classes, e.g. for algebraic or analytic computations are available for all algorithms on equal terms.
With the development and publication of ELKI, we humbly hope to serve the data mining and database research community beneficially. The framework is **free** for scientific usage ("free" as in "open source", see [License](http://elki.dbs.ifi.lmu.de/wiki/License) for details). In case of application of ELKI in scientific publications, we would appreciate credit in form of a [citation](http://elki.dbs.ifi.lmu.de/wiki/Publications) of the appropriate publication (see [our list of publications](http://elki.dbs.ifi.lmu.de/wiki/Publications)), that is, the publication related to the release of ELKI you were using.
The people behind ELKI are documented on the [Team](http://elki.dbs.ifi.lmu.de/wiki/Team) page.
## The ELKI wiki: Tutorials, HowTos, Documentation
Beginners may want to start at the HowTo documents, [Examples](http://elki.dbs.ifi.lmu.de/wiki/Examples) and [Tutorials](http://elki.dbs.ifi.lmu.de/wiki/Tutorial) to help with difficult configuration scenarios and beginning with ELKI development.
This website serves as community development hub and task tracker for both [bug reports](http://elki.dbs.ifi.lmu.de/report/1), [Tutorials](http://elki.dbs.ifi.lmu.de/wiki/Tutorial), [FAQ](http://elki.dbs.ifi.lmu.de/wiki/FAQ), general issues and development tasks.
The most important documentation pages are: [Tutorial](http://elki.dbs.ifi.lmu.de/wiki/Tutorial), searchable [JavaDoc]((http://elki.dbs.ifi.lmu.de/wiki/JavaDoc)), [FAQ](http://elki.dbs.ifi.lmu.de/wiki/FAQ),
[InputFormat](http://elki.dbs.ifi.lmu.de/wiki/InputFormat), [DataTypes](http://elki.dbs.ifi.lmu.de/wiki/DataTypes), [DistanceFunctions](http://elki.dbs.ifi.lmu.de/wiki/DistanceFunctions), [DataSets](http://elki.dbs.ifi.lmu.de/wiki/DataSets), [Development](http://elki.dbs.ifi.lmu.de/wiki/Development), [Parameterization](http://elki.dbs.ifi.lmu.de/wiki/Parameterization),
[Visualization](http://elki.dbs.ifi.lmu.de/wiki/Visualization), [Benchmarking](http://elki.dbs.ifi.lmu.de/wiki/Benchmarking), and the
list of [Algorithms](http://elki.dbs.ifi.lmu.de/wiki/Algorithms) and [RelatedPublications](http://elki.dbs.ifi.lmu.de/wiki/RelatedPublications).
## Getting ELKI: Download and Citation Policy
You can download ELKI including source code on the [Releases](http://elki.dbs.ifi.lmu.de/wiki/Releases) page. ELKI uses the [AGPLv3 License](http://elki.dbs.ifi.lmu.de/wiki/License), a well-known open source license.
There is a list of [Publications](http://elki.dbs.ifi.lmu.de/wiki/Publications) that accompany the ELKI releases. When using ELKI in your scientific work, you should cite the publication corresponding to the ELKI release you are using, to give credit. This also helps to improve the repeatability of your experiments. We would also appreciate if you contributed your algorithm to ELKI to allow others to reproduce your results and compare with your algorithm (which in turn will likely get you citations). We try to document every publication used for implementing ELKI: the page [RelatedPublications](http://elki.dbs.ifi.lmu.de/wiki/RelatedPublications) is generated from the source code annotations.
## Efficiency Benchmarking with ELKI
ELKI is quite fast (see [some of our benchmark results](http://elki.dbs.ifi.lmu.de/wiki/Benchmarking)) but the focus lies on a *broad coverage of algorithms and variations*.
We discourage cross-platform benchmarking, because it is easy to produce misleading results by comparing apples and oranges. For fair comparability, you should implement all algorithms within ELKI, and use the same APIs. We have also observed Java JDK versions have a large impact on the runtime performance. To make your results reproducible, please [cite](http://elki.dbs.ifi.lmu.de/wiki/Publications) the version you have been using. See also [Benchmarking](http://elki.dbs.ifi.lmu.de/wiki/Benchmarking).
## Bug Reports and Contact
You can [browse the open bug reports](http://elki.dbs.ifi.lmu.de/report/1) or [create a new bug report](http://elki.dbs.ifi.lmu.de/newticket).
We also appreciate any comments, suggestions and code contributions. You can contact the core development team by e-mail: `elki () dbs ifi lmu de`
You can also [subscribe to the user mailing list](https://tools.rz.ifi.lmu.de/mailman/listinfo/elki-user) of ELKI, to exchange questions and ideas among other users or to get announcements (e.g., new releases, major changes) by the ELKI team.
Our primary "support" medium is this *community* mailing list. We appreciate if you share experiences and also success stories there that might help other users. This project makes a lot of progress, and information can get outdated rather quickly. If you prefer a web forum, you can *try* asking at [StackOverflow](http://www.stackoverflow.com/), but you should understand that this is a general (and third-party operated) programming community.
## Design Goals
* Extensibility - ELKI has a very modular design. We want to allow arbitrary combinations of data types, distance functions, algorithms, input formats, index structures and evaluations methods
* Contributions - ELKI grows only as fast as people contribute. By having a modular design that allows small contributions such as single distance functions and single algorithms, we can have students and external contributors participate in the progress of ELKI
* Completeness - for an exhaustive comparison of methods, we aim at covering as much published and credited work as we can
* Fairness - It is easy to do an unfair comparison by badly implementing a competitor. We try to implement every method as good as we can, and by publishing the source code allow for external improvements. We try to add all proposed improvements, such as index structures for faster range and kNN queries
* Performance - the modular architecture of ELKI allows optimized versions of algorithms and index structures for acceleration
* Progress - ELKI is changing with every release. To accomodate new features and enhance performance, API breakages are unavoidable. We hope to get a stable API with the 1.0 release, but we are not there yet.
## Building ELKI
ELKI is built using [Maven](https://maven.apache.org/):
mvn package
will produce an executable `jar` file named `elki/target/elki-.jar`.
To build the SVG based visualization add-on, use
mvn -P svg package
which produces an executable `jar` file named `addons/batikvis/target/elki-batik-visualization-.jar`
Required dependencies can be found in the folder `dependency` next to the `jar` file.
elki-release0.7.1/addons/ 0000775 0000000 0000000 00000000000 12657057427 0015273 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/ 0000775 0000000 0000000 00000000000 12657057427 0016124 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/.classpath 0000664 0000000 0000000 00000002253 12657057427 0020111 0 ustar 00root root 0000000 0000000
elki-release0.7.1/addons/3dpc/.gitignore 0000664 0000000 0000000 00000000011 12657057427 0020104 0 ustar 00root root 0000000 0000000 /target/
elki-release0.7.1/addons/3dpc/.project 0000664 0000000 0000000 00000001032 12657057427 0017567 0 ustar 00root root 0000000 0000000
elki-3dpcorg.eclipse.jdt.core.javabuilderorg.eclipse.m2e.core.maven2Builderorg.eclipse.jdt.core.javanatureorg.eclipse.m2e.core.maven2Nature
elki-release0.7.1/addons/3dpc/.settings/ 0000775 0000000 0000000 00000000000 12657057427 0020042 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/.settings/org.eclipse.core.resources.prefs 0000664 0000000 0000000 00000000170 12657057427 0026253 0 ustar 00root root 0000000 0000000 eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/main/resources=UTF-8
encoding/=UTF-8
elki-release0.7.1/addons/3dpc/.settings/org.eclipse.jdt.core.prefs 0000664 0000000 0000000 00000056763 12657057427 0025045 0 ustar 00root root 0000000 0000000 eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.7
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=0
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=0
org.eclipse.jdt.core.formatter.alignment_for_compact_if=0
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=0
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=0
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=0
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
org.eclipse.jdt.core.formatter.blank_lines_before_field=1
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
org.eclipse.jdt.core.formatter.comment.format_header=false
org.eclipse.jdt.core.formatter.comment.format_html=true
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
org.eclipse.jdt.core.formatter.comment.format_source_code=true
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
org.eclipse.jdt.core.formatter.comment.line_length=80
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
org.eclipse.jdt.core.formatter.compact_else_if=true
org.eclipse.jdt.core.formatter.continuation_indentation=2
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_empty_lines=false
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
org.eclipse.jdt.core.formatter.indentation.size=2
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
org.eclipse.jdt.core.formatter.lineSplit=80
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
org.eclipse.jdt.core.formatter.tabulation.char=space
org.eclipse.jdt.core.formatter.tabulation.size=2
org.eclipse.jdt.core.formatter.use_on_off_tags=false
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
elki-release0.7.1/addons/3dpc/.settings/org.eclipse.jdt.ui.prefs 0000664 0000000 0000000 00000013670 12657057427 0024520 0 ustar 00root root 0000000 0000000 eclipse.preferences.version=1
formatter_profile=_ELKI
formatter_settings_version=12
org.eclipse.jdt.ui.javadoc=false
org.eclipse.jdt.ui.text.custom_code_templates=/**\n * @return the ${bare_field_name}\n *//**\n * @param ${param} the ${bare_field_name} to set\n *//**\n * Constructor.\n *\n * ${tags}\n *//**\n * @author ${user}\n *\n * ${tags}\n *//**\n * \n *//**\n * ${tags}\n *//**\n * ${tags}\n * ${see_to_target}\n */${filecomment}\n${package_declaration}\n/*\n This file is part of ELKI\:\n Environment for Developing KDD-Applications Supported by Index-Structures\n\n Copyright (C) ${year}\n Ludwig-Maximilians-Universit\u00E4t M\u00FCnchen\n Lehr- und Forschungseinheit f\u00FCr Datenbanksysteme\n ELKI Development Team\n\n This program is free software\: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http\://www.gnu.org/licenses/>.\n */\n\n${typecomment}\n${type_declaration}\n\n\n\n// ${todo} Auto-generated catch block\nde.lmu.ifi.dbs.elki.logging.LoggingUtil.exception(${exception_var});// ${todo} Auto-generated method stub\n${body_statement}${body_statement}\n// ${todo} Auto-generated constructor stubreturn ${field};${field} \= ${param};
elki-release0.7.1/addons/3dpc/.settings/org.eclipse.m2e.core.prefs 0000664 0000000 0000000 00000000126 12657057427 0024725 0 ustar 00root root 0000000 0000000 activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1
elki-release0.7.1/addons/3dpc/pom.xml 0000664 0000000 0000000 00000002763 12657057427 0017451 0 ustar 00root root 0000000 0000000
4.0.0de.lmu.ifi.dbs.elki0.7.1elki-project../../elki-3dpcjarELKI Data Mining Framework - 3D Parallel Coordinate Trees VisualizationGNU Affero General Public License (AGPL) version 3.0http://www.gnu.org/licenses/agpl-3.0.txtUTF-8de.lmu.ifi.dbs.elkielki${project.version}org.jogamp.jogljogl-all-main2.1.5-01org.jogamp.gluegengluegen-rt-main2.1.5-01de.lmu.ifi.dbs.elkielki-batik-visualization${project.version}
elki-release0.7.1/addons/3dpc/src/ 0000775 0000000 0000000 00000000000 12657057427 0016713 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/ 0000775 0000000 0000000 00000000000 12657057427 0017637 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/ 0000775 0000000 0000000 00000000000 12657057427 0020560 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/ 0000775 0000000 0000000 00000000000 12657057427 0021150 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ 0000775 0000000 0000000 00000000000 12657057427 0021745 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/ 0000775 0000000 0000000 00000000000 12657057427 0022514 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/dbs/ 0000775 0000000 0000000 00000000000 12657057427 0023264 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/dbs/elki/ 0000775 0000000 0000000 00000000000 12657057427 0024210 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/dbs/elki/visualization/ 0000775 0000000 0000000 00000000000 12657057427 0027111 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/dbs/elki/visualization/parallel3d/ 0000775 0000000 0000000 00000000000 12657057427 0031134 5 ustar 00root root 0000000 0000000 OpenGL3DParallelCoordinates.java 0000664 0000000 0000000 00000050700 12657057427 0037105 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/dbs/elki/visualization/parallel3d package de.lmu.ifi.dbs.elki.visualization.parallel3d;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.awt.Font;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;
import javax.media.opengl.DebugGL2;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.glu.GLU;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import com.jogamp.opengl.util.awt.TextRenderer;
import de.lmu.ifi.dbs.elki.data.Clustering;
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.data.model.Model;
import de.lmu.ifi.dbs.elki.data.type.TypeUtil;
import de.lmu.ifi.dbs.elki.data.type.VectorFieldTypeInformation;
import de.lmu.ifi.dbs.elki.database.Database;
import de.lmu.ifi.dbs.elki.database.relation.Relation;
import de.lmu.ifi.dbs.elki.database.relation.RelationUtil;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.math.dimensionsimilarity.DimensionSimilarity;
import de.lmu.ifi.dbs.elki.math.dimensionsimilarity.DimensionSimilarityMatrix;
import de.lmu.ifi.dbs.elki.result.Result;
import de.lmu.ifi.dbs.elki.result.ResultHandler;
import de.lmu.ifi.dbs.elki.result.ResultHierarchy;
import de.lmu.ifi.dbs.elki.result.ResultUtil;
import de.lmu.ifi.dbs.elki.result.ScalesResult;
import de.lmu.ifi.dbs.elki.utilities.Alias;
import de.lmu.ifi.dbs.elki.utilities.ClassGenericsUtil;
import de.lmu.ifi.dbs.elki.utilities.ELKIServiceRegistry;
import de.lmu.ifi.dbs.elki.utilities.documentation.Reference;
import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.EmptyParameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.ListParameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ObjectParameter;
import de.lmu.ifi.dbs.elki.visualization.parallel3d.layout.Layout;
import de.lmu.ifi.dbs.elki.visualization.parallel3d.layout.Layouter3DPC;
import de.lmu.ifi.dbs.elki.visualization.parallel3d.layout.SimilarityBasedLayouter3DPC;
import de.lmu.ifi.dbs.elki.visualization.parallel3d.layout.SimpleCircularMSTLayout3DPC;
import de.lmu.ifi.dbs.elki.visualization.parallel3d.util.Arcball1DOFAdapter;
import de.lmu.ifi.dbs.elki.visualization.parallel3d.util.Simple1DOFCamera;
import de.lmu.ifi.dbs.elki.visualization.parallel3d.util.Simple1DOFCamera.CameraListener;
import de.lmu.ifi.dbs.elki.visualization.parallel3d.util.SimpleMenuOverlay;
import de.lmu.ifi.dbs.elki.visualization.parallel3d.util.SimpleMessageOverlay;
import de.lmu.ifi.dbs.elki.visualization.projections.ProjectionParallel;
import de.lmu.ifi.dbs.elki.visualization.projections.SimpleParallel;
import de.lmu.ifi.dbs.elki.visualization.style.ClusterStylingPolicy;
import de.lmu.ifi.dbs.elki.visualization.style.PropertiesBasedStyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.style.StylingPolicy;
/**
* Simple JOGL2 based parallel coordinates visualization.
*
* Reference:
*
* Elke Achtert, Hans-Peter Kriegel, Erich Schubert, Arthur Zimek:
* Interactive Data Mining with 3D-Parallel-Coordinate-Trees.
* Proceedings of the 2013 ACM International Conference on Management of Data
* (SIGMOD), New York City, NY, 2013.
*
*
* TODO: Improve generics of Layout3DPC.
*
* TODO: Generalize to multiple relations and non-numeric feature vectors.
*
* FIXME: proper depth-sorting of edges. It's not that simple, unfortunately.
*
* @author Erich Schubert
* @since 0.6.0
*
* @param Object type
*/
@Alias({ "3dpc", "3DPC" })
@Reference(authors = "Elke Achtert, Hans-Peter Kriegel, Erich Schubert, Arthur Zimek", title = "Interactive Data Mining with 3D-Parallel-Coordinate-Trees", booktitle = "Proc. of the 2013 ACM International Conference on Management of Data (SIGMOD)", url = "http://dx.doi.org/10.1145/2463676.2463696")
public class OpenGL3DParallelCoordinates implements ResultHandler {
/**
* Logging class.
*/
private static final Logging LOG = Logging.getLogger(OpenGL3DParallelCoordinates.class);
/**
* Settings
*/
Settings settings = new Settings<>();
/**
* Constructor.
*
* @param layout Layout
*/
public OpenGL3DParallelCoordinates(Layouter3DPC super O> layout) {
settings.layout = layout;
}
@Override
public void processNewResult(ResultHierarchy hier, Result newResult) {
boolean nonefound = true;
List> rels = ResultUtil.getRelations(newResult);
for(Relation> rel : rels) {
if(!TypeUtil.NUMBER_VECTOR_FIELD.isAssignableFromType(rel.getDataTypeInformation())) {
continue;
}
@SuppressWarnings("unchecked")
Relation extends O> vrel = (Relation extends O>) rel;
ScalesResult scales = ResultUtil.getScalesResult(vrel);
ProjectionParallel proj = new SimpleParallel(null, scales.getScales());
PropertiesBasedStyleLibrary stylelib = new PropertiesBasedStyleLibrary();
StylingPolicy stylepol = getStylePolicy(hier, stylelib);
new Instance<>(vrel, proj, settings, stylepol, stylelib).run();
nonefound = false;
}
if(nonefound && hier.equals(newResult)) {
LOG.warning("3DPC did not find a number vector field relation to visualize!");
}
}
/**
* Hack: Get/Create the style result.
*
* @return Style result
*/
public StylingPolicy getStylePolicy(ResultHierarchy hier, StyleLibrary stylelib) {
Database db = ResultUtil.findDatabase(hier);
ResultUtil.ensureClusteringResult(db, db);
List> clusterings = ResultUtil.getClusteringResults(db);
if(clusterings.size() > 0) {
return new ClusterStylingPolicy(clusterings.get(0), stylelib);
}
else {
throw new AbortException("No clustering result generated?!?");
}
}
/**
* Class keeping the visualizer settings.
*
* @author Erich Schubert
*
* @param Object type
*/
public static class Settings {
/**
* Similarity measure in use.
*/
public DimensionSimilarity super O> sim;
/**
* Layouting method.
*/
public Layouter3DPC super O> layout;
/**
* Line width.
*/
public float linewidth = 2f;
/**
* Texture width.
*/
public int texwidth = 1 << 8;
/**
* Texture height.
*/
public int texheight = 1 << 10;
/**
* Number of additional mipmaps to generate.
*/
public int mipmaps = 1;
}
/**
* Visualizer instance.
*
* @author Erich Schubert
*
* @param Object type
*/
public static class Instance implements GLEventListener {
/**
* Flag to enable debug rendering.
*/
static final boolean DEBUG = false;
/**
* Frame
*/
JFrame frame = null;
/**
* GLU utility class.
*/
GLU glu;
/**
* 3D parallel coordinates renderer.
*/
private Parallel3DRenderer prenderer;
/**
* The OpenGL canvas
*/
GLCanvas canvas;
/**
* Arcball controller.
*/
Arcball1DOFAdapter arcball;
/**
* Menu overlay.
*/
SimpleMenuOverlay menuOverlay;
/**
* Message overlay.
*/
SimpleMessageOverlay messageOverlay;
/**
* Handler to open the menu.
*/
MouseAdapter menuStarter;
/**
* Current state.
*/
State state = State.PREPARATION;
/**
* States of the UI.
*
* @author Erich Schubert
*
* @apiviz.exclude
*/
protected static enum State { //
PREPARATION, // Preparation phase
EXPLORE, // Exploration phase (rotate etc.)
MENU, // Menu open
}
/**
* Shared data for visualization modules.
*
* @author Erich Schubert
*
* @param Relation data type
*/
protected static class Shared {
/**
* Dimensionality.
*/
int dim;
/**
* Relation to visualize
*/
Relation extends O> rel;
/**
* Axis labels
*/
String[] labels;
/**
* Projection
*/
ProjectionParallel proj;
/**
* Style result
*/
StylingPolicy stylepol;
/**
* Style library
*/
StyleLibrary stylelib;
/**
* Layout
*/
Layout layout;
/**
* Settings
*/
Settings settings;
/**
* Camera handling class
*/
Simple1DOFCamera camera;
/**
* Text renderer
*/
TextRenderer textrenderer;
/**
* Current similarity matrix.
*/
DimensionSimilarityMatrix mat;
};
Shared shared = new Shared<>();
/**
* Constructor.
*
* @param rel Relation
* @param proj Projection
* @param settings Settings
* @param style Style result
*/
public Instance(Relation extends O> rel, ProjectionParallel proj, Settings settings, StylingPolicy stylepol, StyleLibrary stylelib) {
super();
this.shared.dim = RelationUtil.dimensionality(rel);
this.shared.rel = rel;
this.shared.proj = proj;
this.shared.stylelib = stylelib;
this.shared.stylepol = stylepol;
this.shared.settings = settings;
// Labels:
this.shared.labels = new String[this.shared.dim];
{
VectorFieldTypeInformation extends O> vrel = RelationUtil.assumeVectorField(rel);
for(int i = 0; i < this.shared.dim; i++) {
this.shared.labels[i] = vrel.getLabel(i);
}
}
this.prenderer = new Parallel3DRenderer<>(shared);
this.menuOverlay = new SimpleMenuOverlay() {
@Override
public void menuItemClicked(int item) {
if(item < 0) {
switchState(State.EXPLORE);
return;
}
final String name = menuOverlay.getOptions().get(item);
if(name == null) {
switchState(State.EXPLORE);
return;
}
LOG.debug("Relayout chosen: " + name);
relayout(name);
}
};
this.menuStarter = new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if(State.EXPLORE.equals(state)) {
if(e.getButton() == MouseEvent.BUTTON3) {
switchState(State.MENU);
// e.consume();
}
}
}
};
this.messageOverlay = new SimpleMessageOverlay();
// Init menu for SIGMOD demo. TODO: make more flexible.
{
ArrayList options = menuOverlay.getOptions();
for(Class> clz : ELKIServiceRegistry.findAllImplementations(Layouter3DPC.class)) {
options.add(clz.getSimpleName());
}
if(options.size() > 0) {
options.add(null); // Spacer.
}
for(Class> clz : ELKIServiceRegistry.findAllImplementations(DimensionSimilarity.class)) {
options.add(clz.getSimpleName());
}
}
GLProfile glp = GLProfile.getDefault();
GLCapabilities caps = new GLCapabilities(glp);
caps.setDoubleBuffered(true);
canvas = new GLCanvas(caps);
canvas.addGLEventListener(this);
frame = new JFrame("ELKI 3D Parallel Coordinate Visualization");
frame.setSize(600, 600);
frame.add(canvas);
}
void initLabels() {
// Labels:
shared.labels = new String[shared.dim];
for(int i = 0; i < shared.dim; i++) {
shared.labels[i] = RelationUtil.getColumnLabel(shared.rel, i);
}
}
@SuppressWarnings("unchecked")
protected void relayout(String parname) {
try {
final Class> layoutc = ELKIServiceRegistry.findImplementation(Layouter3DPC.class, parname);
if(layoutc != null) {
ListParameterization params = new ListParameterization();
if(shared.settings.sim != null) {
params.addParameter(SimilarityBasedLayouter3DPC.SIM_ID, shared.settings.sim);
}
shared.settings.layout = ClassGenericsUtil.tryInstantiate(Layouter3DPC.class, layoutc, params);
switchState(State.PREPARATION);
startLayoutThread();
return;
}
}
catch(Exception e) {
LOG.exception(e);
// Try with Dimension Similarity instead.
}
try {
final Class> simc = ELKIServiceRegistry.findImplementation(DimensionSimilarity.class, parname);
if(simc != null) {
shared.settings.sim = ClassGenericsUtil.tryInstantiate(DimensionSimilarity.class, simc, new EmptyParameterization());
if(!(shared.settings.layout instanceof SimilarityBasedLayouter3DPC)) {
ListParameterization params = new ListParameterization();
params.addParameter(SimilarityBasedLayouter3DPC.SIM_ID, shared.settings.sim);
shared.settings.layout = ClassGenericsUtil.tryInstantiate(Layouter3DPC.class, SimpleCircularMSTLayout3DPC.class, params);
}
// Clear similarity matrix:
shared.mat = null;
switchState(State.PREPARATION);
startLayoutThread();
return;
}
}
catch(Exception e) {
LOG.exception(e);
}
// TODO: improve menu, to allow pretty names and map name -> class.
LOG.warning("Menu parameter did not map to a class name - wrong package?");
}
private void startLayoutThread() {
new Thread() {
@Override
public void run() {
messageOverlay.setMessage("Computing axis similarities and layout...");
if(shared.settings.sim != null && shared.settings.layout instanceof SimilarityBasedLayouter3DPC) {
@SuppressWarnings("unchecked")
final SimilarityBasedLayouter3DPC layouter = (SimilarityBasedLayouter3DPC) shared.settings.layout;
if(shared.mat == null) {
messageOverlay.setMessage("Recomputing similarity matrix.");
shared.mat = DimensionSimilarityMatrix.make(shared.dim);
shared.settings.sim.computeDimensionSimilarites(shared.rel, shared.rel.getDBIDs(), shared.mat);
}
messageOverlay.setMessage("Recomputing layout using similarity matrix.");
final Layout newlayout = layouter.layout(shared.dim, shared.mat);
setLayout(newlayout);
}
else {
messageOverlay.setMessage("Recomputing layout.");
final Layout newlayout = shared.settings.layout.layout(shared.rel);
setLayout(newlayout);
}
}
}.start();
}
public void run() {
assert (frame != null);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent e) {
stop();
}
});
startLayoutThread();
}
public void stop() {
frame = null;
}
@Override
public void init(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
if(DEBUG) {
gl = new DebugGL2(gl);
drawable.setGL(gl);
}
// As we aren't really rendering models, but just drawing,
// We do not need to set up a lot.
gl.glClearColor(1f, 1f, 1f, 1f);
gl.glDisable(GL.GL_DEPTH_TEST);
gl.glDisable(GL.GL_CULL_FACE);
glu = new GLU();
shared.camera = new Simple1DOFCamera(glu);
shared.camera.addCameraListener(new CameraListener() {
@Override
public void cameraChanged() {
canvas.display();
}
});
// Setup arcball:
arcball = new Arcball1DOFAdapter(shared.camera);
shared.textrenderer = new TextRenderer(new Font(Font.SANS_SERIF, Font.BOLD, 36));
// Ensure listeners.
switchState(state);
}
/**
* Switch the current state.
*
* @param newstate State to switch to.
*/
void switchState(State newstate) {
// Reset mouse listeners
canvas.removeMouseListener(menuStarter);
canvas.removeMouseListener(menuOverlay);
canvas.removeMouseListener(arcball);
canvas.removeMouseMotionListener(arcball);
canvas.removeMouseWheelListener(arcball);
switch(newstate){
case EXPLORE: {
canvas.addMouseListener(menuStarter);
canvas.addMouseListener(arcball);
canvas.addMouseMotionListener(arcball);
canvas.addMouseWheelListener(arcball);
break;
}
case MENU: {
canvas.addMouseListener(menuOverlay);
break;
}
case PREPARATION: {
// No listeners.
break;
}
}
if(state != newstate) {
this.state = newstate;
canvas.repaint();
}
}
@Override
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
shared.camera.setRatio(width / (double) height);
messageOverlay.setSize(width, height);
menuOverlay.setSize(width, height);
}
@Override
public void display(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glClear(GL.GL_COLOR_BUFFER_BIT /* | GL.GL_DEPTH_BUFFER_BIT */);
if(shared.layout != null) {
int res = prenderer.prepare(gl);
if(res == 1) {
// Request a repaint, to generate the next texture.
canvas.repaint();
}
if(res == 2) {
messageOverlay.setMessage("Texture rendering completed.");
switchState(State.EXPLORE);
}
}
shared.camera.apply(gl);
if(shared.layout != null) {
prenderer.drawParallelPlot(drawable, gl);
}
if(DEBUG) {
arcball.debugRender(gl);
}
if(State.MENU.equals(state)) {
menuOverlay.render(gl);
}
if(State.PREPARATION.equals(state)) {
messageOverlay.render(gl);
}
}
/**
* Callback from layouting thread.
*
* @param newlayout New layout.
*/
protected void setLayout(final Layout newlayout) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
shared.layout = newlayout;
prenderer.forgetTextures(null);
messageOverlay.setMessage("Rendering Textures.");
canvas.repaint();
}
});
}
@Override
public void dispose(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
prenderer.forgetTextures(gl);
}
}
/**
* Parameterization class.
*
* @author Erich Schubert
*
* @apiviz.exclude
*
* @param Object type
*/
public static class Parameterizer extends AbstractParameterizer {
/**
* Option for layouting method
*/
public static final OptionID LAYOUT_ID = new OptionID("parallel3d.layout", "Layouting method for 3DPC.");
/**
* Similarity measure
*/
Layouter3DPC layout;
@Override
protected void makeOptions(Parameterization config) {
super.makeOptions(config);
ObjectParameter> layoutP = new ObjectParameter<>(LAYOUT_ID, Layouter3DPC.class, SimpleCircularMSTLayout3DPC.class);
if(config.grab(layoutP)) {
layout = layoutP.instantiateClass(config);
}
}
@Override
protected OpenGL3DParallelCoordinates makeInstance() {
return new OpenGL3DParallelCoordinates<>(layout);
}
}
}
Parallel3DRenderer.java 0000664 0000000 0000000 00000046307 12657057427 0035344 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/dbs/elki/visualization/parallel3d package de.lmu.ifi.dbs.elki.visualization.parallel3d;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.awt.Color;
import java.awt.geom.Rectangle2D;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.Arrays;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.math.MathUtil;
import de.lmu.ifi.dbs.elki.math.scales.LinearScale;
import de.lmu.ifi.dbs.elki.utilities.documentation.Reference;
import de.lmu.ifi.dbs.elki.utilities.io.ByteArrayUtil;
import de.lmu.ifi.dbs.elki.utilities.pairs.DoubleIntPair;
import de.lmu.ifi.dbs.elki.utilities.pairs.IntIntPair;
import de.lmu.ifi.dbs.elki.visualization.colors.ColorLibrary;
import de.lmu.ifi.dbs.elki.visualization.parallel3d.OpenGL3DParallelCoordinates.Instance.Shared;
import de.lmu.ifi.dbs.elki.visualization.parallel3d.layout.Layout;
import de.lmu.ifi.dbs.elki.visualization.parallel3d.layout.Layout.Node;
import de.lmu.ifi.dbs.elki.visualization.style.ClassStylingPolicy;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.style.StylingPolicy;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
/**
* Renderer for 3D parallel plots.
*
* The tricky part here is the vertex buffer layout. We are drawing lines, so we
* need two vertices for each macro edge (edge between axes in the plot). We
* furthermore need the following properties: we need to draw edges sorted by
* depth to allow alpha and smoothing to work, and we need to be able to have
* different colors for clusters. An efficient batch therefore will consist of
* one edge-color combination. The input data comes in color-object ordering, so
* we need to seek through the edges when writing the buffer.
*
* In total, we have 2 * obj.size * edges.size vertices.
*
* Where obj.size = sum(col.sizes)
*
* Reference:
*
* Elke Achtert, Hans-Peter Kriegel, Erich Schubert, Arthur Zimek:
* Interactive Data Mining with 3D-Parallel-Coordinate-Trees.
* Proceedings of the 2013 ACM International Conference on Management of Data
* (SIGMOD), New York City, NY, 2013.
*
*
* TODO: generalize to non-numeric features and scales.
*
* @author Erich Schubert
* @since 0.6.0
*
* @param Object type
*/
@Reference(authors = "Elke Achtert, Hans-Peter Kriegel, Erich Schubert, Arthur Zimek", title = "Interactive Data Mining with 3D-Parallel-Coordinate-Trees", booktitle = "Proc. of the 2013 ACM International Conference on Management of Data (SIGMOD)", url = "http://dx.doi.org/10.1145/2463676.2463696")
public class Parallel3DRenderer {
/**
* Logging class.
*/
private static final Logging LOG = Logging.getLogger(Parallel3DRenderer.class);
/**
* Shared data.
*/
Shared shared;
/**
* Prerendered textures.
*/
private int[] textures;
/**
* Number of completely rendered textures.
*/
private int completedTextures = 0;
/**
* Depth indexes of axes.
*/
private int[] dindex;
/**
* Color table.
*/
float[] colors;
/**
* Axes sorting array.
*/
DoubleIntPair[] axes;
/**
* Vertex buffer.
*/
int[] vbi = new int[] { -1 };
/**
* Framebuffer for render-to-texture
*/
int[] frameBufferID = new int[] { -1 };
/**
* Constructor.
*
* @param shared Shared data.
*/
protected Parallel3DRenderer(Shared shared) {
super();
this.shared = shared;
this.dindex = new int[shared.dim];
axes = new DoubleIntPair[shared.dim];
for (int i = 0; i < shared.dim; i++) {
axes[i] = new DoubleIntPair(0.0, 0);
}
}
protected int prepare(GL2 gl) {
if (completedTextures < 0) {
if (textures != null) {
gl.glDeleteTextures(textures.length, textures, 0);
textures = null;
}
completedTextures = 0;
}
if (completedTextures >= shared.layout.edges.size()) {
return 0;
}
if (!LOG.isDebugging()) {
renderTexture(gl, completedTextures);
} else {
long start = System.nanoTime();
renderTexture(gl, completedTextures);
long end = System.nanoTime();
LOG.debug("Time to render texture: " + (end - start) / 1e6 + " ms.");
}
return (completedTextures < shared.layout.edges.size()) ? 1 : 2;
}
protected void drawParallelPlot(GLAutoDrawable drawable, GL2 gl) {
// Sort axes by sq. distance from camera, front-to-back:
sortAxes();
// Sort edges by the maximum (foreground) index.
IntIntPair[] edgesort = sortEdges(dindex);
if (textures != null) {
gl.glShadeModel(GL2.GL_FLAT);
// Render spider web:
gl.glLineWidth(shared.settings.linewidth); // outside glBegin!
gl.glBegin(GL.GL_LINES);
gl.glColor4f(0f, 0f, 0f, 1f);
for (Layout.Edge edge : shared.layout.edges) {
Node n1 = shared.layout.getNode(edge.dim1), n2 = shared.layout.getNode(edge.dim2);
gl.glVertex3d(n1.getX(), n1.getY(), 0f);
gl.glVertex3d(n2.getX(), n2.getY(), 0f);
}
gl.glEnd();
// Draw axes and 3DPC:
for (int i = 0; i < shared.dim; i++) {
final int d = axes[i].second;
final Node node1 = shared.layout.getNode(d);
// Draw edge textures
for (IntIntPair pair : edgesort) {
// Not yet available?
if (pair.second >= completedTextures) {
continue;
}
// Other axis must have a smaller index.
if (pair.first >= i) {
continue;
}
Layout.Edge edge = shared.layout.edges.get(pair.second);
// Must involve the current axis.
if (edge.dim1 != d && edge.dim2 != d) {
continue;
}
int od = axes[pair.first].second;
gl.glEnable(GL.GL_TEXTURE_2D);
gl.glColor4f(1f, 1f, 1f, 1f);
final Node node2 = shared.layout.getNode(od);
gl.glBindTexture(GL.GL_TEXTURE_2D, textures[pair.second]);
gl.glBegin(GL2.GL_QUADS);
gl.glTexCoord2d((edge.dim1 == d) ? 0f : 1f, 0f);
gl.glVertex3d(node1.getX(), node1.getY(), 0f);
gl.glTexCoord2d((edge.dim1 == d) ? 0f : 1f, 1f);
gl.glVertex3d(node1.getX(), node1.getY(), 1f);
gl.glTexCoord2d((edge.dim1 != d) ? 0f : 1f, 1f);
gl.glVertex3d(node2.getX(), node2.getY(), 1f);
gl.glTexCoord2d((edge.dim1 != d) ? 0f : 1f, 0f);
gl.glVertex3d(node2.getX(), node2.getY(), 0f);
gl.glEnd();
gl.glDisable(GL.GL_TEXTURE_2D);
}
// Draw axis
gl.glLineWidth(shared.settings.linewidth); // outside glBegin!
gl.glBegin(GL.GL_LINES);
gl.glColor4f(0f, 0f, 0f, 1f);
gl.glVertex3d(node1.getX(), node1.getY(), 0f);
gl.glVertex3d(node1.getX(), node1.getY(), 1f);
gl.glEnd();
// Draw ticks.
LinearScale scale = shared.proj.getAxisScale(d);
gl.glPointSize(shared.settings.linewidth * 2f);
gl.glBegin(GL.GL_POINTS);
for (double tick = scale.getMin(); tick <= scale.getMax() + scale.getRes() / 10; tick += scale.getRes()) {
gl.glVertex3d(node1.getX(), node1.getY(), scale.getScaled(tick));
}
gl.glEnd();
}
}
// Render labels
renderLabels(gl, edgesort);
}
void renderTexture(GL2 gl, int edge) {
assert (edge == completedTextures);
// Setup color table:
prepareColors(shared.stylepol);
// Setup buffer IDs:
if (vbi[0] < 0) {
gl.glGenBuffers(1, vbi, 0);
// Buffer for coordinates.
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vbi[0]);
gl.glBufferData(GL.GL_ARRAY_BUFFER, shared.rel.size() // Number of lines *
* 2 // 2 Points *
* 5 // 2 coordinates + 3 color
* ByteArrayUtil.SIZE_FLOAT, null, GL2.GL_DYNAMIC_DRAW);
} else {
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vbi[0]);
}
// Generate textures:
if (textures == null) {
textures = new int[shared.layout.edges.size()];
gl.glGenTextures(textures.length, textures, 0);
}
// Get a framebuffer:
if (frameBufferID[0] < 0) {
gl.glGenFramebuffers(1, frameBufferID, 0);
}
gl.glPushAttrib(GL2.GL_TEXTURE_BIT | GL2.GL_VIEWPORT_BIT);
gl.glPushMatrix();
gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, frameBufferID[0]);
{
Layout.Edge e = shared.layout.edges.get(edge);
gl.glBindTexture(GL.GL_TEXTURE_2D, textures[edge]);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP_TO_EDGE);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP_TO_EDGE);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_LINEAR);
gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_MODULATE);
// Reserve texture image data:
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL2.GL_RGBA16, //
shared.settings.texwidth, shared.settings.texheight, 0, // Size
GL2.GL_RGBA, GL2.GL_FLOAT, null);
gl.glViewport(0, 0, shared.settings.texwidth, shared.settings.texheight);
// Attach 2D texture to this FBO
gl.glFramebufferTexture2D(GL2.GL_FRAMEBUFFER, GL2.GL_COLOR_ATTACHMENT0, //
GL.GL_TEXTURE_2D, textures[edge], 0);
if (gl.glCheckFramebufferStatus(GL2.GL_FRAMEBUFFER) != GL2.GL_FRAMEBUFFER_COMPLETE) {
LOG.warning("glCheckFramebufferStatus: " + gl.glCheckFramebufferStatus(GL2.GL_FRAMEBUFFER));
}
gl.glDisable(GL2.GL_LIGHTING);
gl.glDisable(GL.GL_CULL_FACE);
gl.glDisable(GL.GL_DEPTH_TEST);
gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glLoadIdentity();
gl.glOrtho(0f, 1f, 0f, StyleLibrary.SCALE, -1, 1);
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glClearColor(1f, 1f, 1f, .0f);
gl.glClear(GL2.GL_COLOR_BUFFER_BIT);
gl.glShadeModel(GL2.GL_SMOOTH);
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
gl.glEnable(GL.GL_BLEND);
gl.glEnable(GL.GL_LINE_SMOOTH);
gl.glLineWidth(shared.settings.linewidth);
if (shared.stylepol instanceof ClassStylingPolicy) {
ClassStylingPolicy csp = (ClassStylingPolicy) shared.stylepol;
final int mincolor = csp.getMinStyle();
ByteBuffer vbytebuffer = gl.glMapBuffer(GL.GL_ARRAY_BUFFER, GL2.GL_WRITE_ONLY);
FloatBuffer vertices = vbytebuffer.order(ByteOrder.nativeOrder()).asFloatBuffer();
int p = 0;
for (DBIDIter it = shared.rel.iterDBIDs(); it.valid(); it.advance(), p += 2) {
final O vec = shared.rel.get(it);
final int c = (csp.getStyleForDBID(it) - mincolor) * 3;
final float v1 = (float) shared.proj.fastProjectDataToRenderSpace(vec.doubleValue(e.dim1), e.dim1);
final float v2 = (float) shared.proj.fastProjectDataToRenderSpace(vec.doubleValue(e.dim2), e.dim2);
vertices.put(0.f);
vertices.put(v1);
vertices.put(colors[c]);
vertices.put(colors[c + 1]);
vertices.put(colors[c + 2]);
vertices.put(1.f);
vertices.put(v2);
vertices.put(colors[c]);
vertices.put(colors[c + 1]);
vertices.put(colors[c + 2]);
}
vertices.flip();
gl.glUnmapBuffer(GL.GL_ARRAY_BUFFER);
gl.glColor4f(1f, 1f, 1f, 1f);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vbi[0]);
gl.glVertexPointer(2, GL.GL_FLOAT, 5 * ByteArrayUtil.SIZE_FLOAT, 0);
gl.glEnableClientState(GL2.GL_VERTEX_ARRAY);
gl.glColorPointer(3, GL.GL_FLOAT, 5 * ByteArrayUtil.SIZE_FLOAT, 2 * ByteArrayUtil.SIZE_FLOAT);
gl.glEnableClientState(GL2.GL_COLOR_ARRAY);
gl.glDrawArrays(GL.GL_LINES, 0, p);
gl.glDisableClientState(GL2.GL_COLOR_ARRAY);
gl.glDisableClientState(GL2.GL_VERTEX_ARRAY);
} else {
ByteBuffer vbytebuffer = gl.glMapBuffer(GL.GL_ARRAY_BUFFER, GL2.GL_WRITE_ONLY);
FloatBuffer vertices = vbytebuffer.order(ByteOrder.nativeOrder()).asFloatBuffer();
int p = 0;
for (DBIDIter it = shared.rel.iterDBIDs(); it.valid(); it.advance(), p += 2) {
final O vec = shared.rel.get(it);
final float v1 = (float) shared.proj.fastProjectDataToRenderSpace(vec.doubleValue(e.dim1), e.dim1);
final float v2 = (float) shared.proj.fastProjectDataToRenderSpace(vec.doubleValue(e.dim2), e.dim2);
vertices.put(0.f);
vertices.put(v1);
vertices.put(1.f);
vertices.put(v2);
}
vertices.flip();
gl.glUnmapBuffer(GL.GL_ARRAY_BUFFER);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vbi[0]);
gl.glEnableClientState(GL2.GL_VERTEX_ARRAY);
gl.glVertexPointer(2, GL.GL_FLOAT, 0, 0);
gl.glColor3f(colors[0], colors[1], colors[2]);
gl.glDrawArrays(GL.GL_LINES, 0, p);
gl.glDisableClientState(GL2.GL_VERTEX_ARRAY);
}
if (shared.settings.mipmaps > 0) {
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL2.GL_TEXTURE_BASE_LEVEL, 0);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAX_LEVEL, shared.settings.mipmaps);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_LINEAR);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR_MIPMAP_LINEAR);
gl.glHint(GL.GL_GENERATE_MIPMAP_HINT, GL.GL_NICEST);
gl.glGenerateMipmap(GL.GL_TEXTURE_2D);
}
gl.glBindTexture(GL.GL_TEXTURE_2D, 0);
if (!gl.glIsTexture(textures[0])) {
LOG.warning("Generating texture failed!");
}
}
// Switch back to the default framebuffer.
gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, 0);
gl.glPopMatrix();
gl.glPopAttrib();
++completedTextures;
if (completedTextures == shared.layout.edges.size()) {
// Free vertex buffer
gl.glDeleteBuffers(vbi.length, vbi, 0);
vbi[0] = -1;
// Free framebuffer
gl.glDeleteFramebuffers(1, frameBufferID, 0);
frameBufferID[0] = -1;
}
}
private void prepareColors(final StylingPolicy sp) {
if (colors == null) {
final ColorLibrary cols = shared.stylelib.getColorSet(StyleLibrary.PLOT);
if (sp instanceof ClassStylingPolicy) {
ClassStylingPolicy csp = (ClassStylingPolicy) sp;
final int maxStyle = csp.getMaxStyle();
colors = new float[maxStyle * 3];
for (int c = 0, s = csp.getMinStyle(); s < maxStyle; c += 3, s++) {
Color col = SVGUtil.stringToColor(cols.getColor(s));
colors[c + 0] = col.getRed() / 255.f;
colors[c + 1] = col.getGreen() / 255.f;
colors[c + 2] = col.getBlue() / 255.f;
}
} else {
// Render in black.
colors = new float[] { 0f, 0f, 0f };
}
}
}
protected void forgetTextures(GL gl) {
if (gl == null) {
completedTextures = -1;
} else {
if (textures != null) {
gl.glDeleteTextures(textures.length, textures, 0);
textures = null;
}
completedTextures = 0;
}
}
/**
* Depth-sort the axes.
*
* @param axes Sorted list of (depth, axis)
*/
private void sortAxes() {
for (int d = 0; d < shared.dim; d++) {
double dist = shared.camera.squaredDistanceFromCamera(shared.layout.getNode(d).getX(), shared.layout.getNode(d).getY());
axes[d].first = -dist;
axes[d].second = d;
}
Arrays.sort(axes);
for (int i = 0; i < shared.dim; i++) {
dindex[axes[i].second] = i;
}
}
/**
* Sort the edges for rendering.
*
* FIXME: THIS STILL HAS ERRORS SOMETIME!
*
* @param dindex depth index of axes.
* @return Sorted array of (minaxis, edgeid)
*/
private IntIntPair[] sortEdges(int[] dindex) {
IntIntPair[] edgesort = new IntIntPair[shared.layout.edges.size()];
int e = 0;
for (Layout.Edge edge : shared.layout.edges) {
int i1 = dindex[edge.dim1], i2 = dindex[edge.dim2];
edgesort[e] = new IntIntPair(Math.min(i1, i2), e);
e++;
}
Arrays.sort(edgesort);
return edgesort;
}
private void renderLabels(GL2 gl, IntIntPair[] edgesort) {
shared.textrenderer.begin3DRendering();
// UNDO the camera rotation. This will mess up text orientation!
gl.glRotatef((float) MathUtil.rad2deg(shared.camera.getRotationZ()), 0.f, 0.f, 1.f);
// Rotate to have the text face the camera direction, which looks +Y
// While the text will be visible from +Z and +Y is baseline.
gl.glRotatef(90.f, 1.f, 0.f, 0.f);
// HalfPI: 180 degree extra rotation, for text orientation.
double cos = Math.cos(shared.camera.getRotationZ()), sin = Math.sin(shared.camera.getRotationZ());
shared.textrenderer.setColor(0.0f, 0.0f, 0.0f, 1.0f);
float defaultscale = .01f / (float) Math.sqrt(shared.dim);
final float targetwidth = .2f; // TODO: div depth?
final float minratio = 8.f; // Assume all text is at least this width
for (int i = 0; i < shared.dim; i++) {
if (shared.labels[i] != null) {
Rectangle2D b = shared.textrenderer.getBounds(shared.labels[i]);
float scale = defaultscale;
if (Math.max(b.getWidth(), b.getHeight() * minratio) * scale > targetwidth) {
scale = targetwidth / (float) Math.max(b.getWidth(), b.getHeight() * minratio);
}
float w = (float) b.getWidth() * scale;
// Rotate manually, in x-z plane
float x = (float) (cos * shared.layout.getNode(i).getX() + sin * shared.layout.getNode(i).getY());
float y = (float) (-sin * shared.layout.getNode(i).getX() + cos * shared.layout.getNode(i).getY());
shared.textrenderer.draw3D(shared.labels[i], (x - w * .5f), 1.01f, -y, scale);
}
}
// Show depth indexes on debug:
if (OpenGL3DParallelCoordinates.Instance.DEBUG) {
shared.textrenderer.setColor(1f, 0f, 0f, 1f);
for (IntIntPair pair : edgesort) {
Layout.Edge edge = shared.layout.edges.get(pair.second);
final Node node1 = shared.layout.getNode(edge.dim1);
final Node node2 = shared.layout.getNode(edge.dim2);
final double mx = 0.5 * (node1.getX() + node2.getX());
final double my = 0.5 * (node1.getY() + node2.getY());
// Rotate manually, in x-z plane
float x = (float) (cos * mx + sin * my);
float y = (float) (-sin * mx + cos * my);
shared.textrenderer.draw3D(Integer.toString(pair.first), (x - defaultscale * .5f), 1.01f, -y, .5f * defaultscale);
}
}
shared.textrenderer.end3DRendering();
}
}
elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/dbs/elki/visualization/parallel3d/layout/ 0000775 0000000 0000000 00000000000 12657057427 0032451 5 ustar 00root root 0000000 0000000 AbstractLayout3DPC.java 0000664 0000000 0000000 00000017667 12657057427 0036631 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/dbs/elki/visualization/parallel3d/layout package de.lmu.ifi.dbs.elki.visualization.parallel3d.layout;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.database.relation.Relation;
import de.lmu.ifi.dbs.elki.database.relation.RelationUtil;
import de.lmu.ifi.dbs.elki.math.dimensionsimilarity.CovarianceDimensionSimilarity;
import de.lmu.ifi.dbs.elki.math.dimensionsimilarity.DimensionSimilarity;
import de.lmu.ifi.dbs.elki.math.dimensionsimilarity.DimensionSimilarityMatrix;
import de.lmu.ifi.dbs.elki.math.geometry.PrimsMinimumSpanningTree;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ObjectParameter;
import de.lmu.ifi.dbs.elki.visualization.parallel3d.layout.Layout.Edge;
/**
* Abstract class for dimension similarity based layouters.
*
* @author Erich Schubert
* @since 0.6.0
*/
public abstract class AbstractLayout3DPC implements SimilarityBasedLayouter3DPC {
/**
* Similarity measure
*/
DimensionSimilarity super NumberVector> sim = CovarianceDimensionSimilarity.STATIC;
/**
* Constructor.
*
* @param sim Similarity measure
*/
public AbstractLayout3DPC(DimensionSimilarity super NumberVector> sim) {
super();
this.sim = sim;
}
@Override
public DimensionSimilarity super NumberVector> getSimilarity() {
return sim;
}
@Override
public Layout layout(Relation extends NumberVector> rel) {
int dim = RelationUtil.dimensionality(rel);
DimensionSimilarityMatrix mat = DimensionSimilarityMatrix.make(dim);
sim.computeDimensionSimilarites(rel, rel.getDBIDs(), mat);
return layout(dim, mat);
}
@Override
public abstract Layout layout(final int dim, DimensionSimilarityMatrix mat);
/**
* Build the minimum spanning tree.
*
* @param mat Similarity matrix
* @param layout Layout to write to
* @return Root node id
*/
protected N buildSpanningTree(DimensionSimilarityMatrix mat, Layout layout) {
assert(layout.edges == null || layout.edges.size() == 0);
int[] iedges = PrimsMinimumSpanningTree.processDense(mat, DimensionSimilarityMatrix.PRIM_ADAPTER);
int root = findOptimalRoot(iedges);
// Convert edges:
ArrayList edges = new ArrayList<>(iedges.length >> 1);
for(int i = 0; i < iedges.length; i += 2) {
edges.add(new Edge(iedges[i], iedges[i + 1]));
}
layout.edges = edges;
// Prefill nodes array with nulls.
ArrayList nodes = new ArrayList<>(mat.size());
for(int i = 0; i < mat.size(); i++) {
nodes.add(null);
}
layout.nodes = nodes;
N rootnode = buildTree(iedges, root, -1, nodes);
return rootnode;
}
abstract N makeNode(int dim, List children);
/**
* Recursive tree build method.
*
* @param msg Minimum spanning graph
* @param cur Current node
* @param parent Parent node
* @param nodes Nodes array to fill - must be preinitialized with nulls!
* @return Tree of nodes
*/
protected N buildTree(int[] msg, int cur, int parent, ArrayList nodes) {
// Count the number of children:
int c = 0;
for(int i = 0; i < msg.length; i += 2) {
if(msg[i] == cur && msg[i + 1] != parent) {
c++;
}
if(msg[i + 1] == cur && msg[i] != parent) {
c++;
}
}
// Build children:
List children;
if(c > 0) {
children = new ArrayList<>(c);
}
else {
children = Collections.emptyList();
}
for(int i = 0; i < msg.length; i += 2) {
if(msg[i] == cur && msg[i + 1] != parent) {
c--;
children.add(buildTree(msg, msg[i + 1], cur, nodes));
}
if(msg[i + 1] == cur && msg[i] != parent) {
c--;
children.add(buildTree(msg, msg[i], cur, nodes));
}
}
assert(c == 0);
N node = makeNode(cur, children);
nodes.set(cur, node);
return node;
}
/**
* Compute the depth of the graph.
*
* @param node Current node
* @return Depth
*/
protected int maxDepth(Layout.Node node) {
int depth = 0;
for(int i = 0; i < node.numChildren(); i++) {
Layout.Node child = node.getChild(i);
depth = Math.max(depth, maxDepth(child));
}
return depth + 1;
}
/**
* Abstract node implementation.
*
* @author Erich Schubert
*
* @param Final node type
*/
public static class AbstractNode> implements Layout.Node {
/**
* Dimension represented by this node.
*/
public int dim;
/**
* Coordinates
*/
public double x, y;
/**
* Children
*/
public List children;
/**
* Constructor.
*
* @param dim Dimension number
* @param children Children
*/
public AbstractNode(int dim, List children) {
this.dim = dim;
this.children = children;
}
@Override
public int getDim() {
return dim;
}
@Override
public double getX() {
return x;
}
@Override
public double getY() {
return y;
}
@Override
public N getChild(int off) {
return children.get(off);
}
@Override
public int numChildren() {
return children.size();
}
}
/**
* Find the "optimal" root of a spanning tree. Optimal in the sense of: one of
* the most central nodes.
*
* This uses a simple message passing approach. Every node that has only one
* unset neighbor will emit a message to this neighbor. The node last to emit
* wins.
*
* @param msg Minimum spanning graph.
* @return
*/
public static int findOptimalRoot(int[] msg) {
final int size = (msg.length >> 1) + 1;
int[] depth = new int[size];
int[] missing = new int[size];
// We shouldn't need more iterations in any case ever.
int root = -1;
for(int i = 1; i < size; i++) {
boolean active = false;
for(int e = 0; e < msg.length; e += 2) {
if(depth[msg[e]] == 0) {
missing[msg[e + 1]]++;
}
if(depth[msg[e + 1]] == 0) {
missing[msg[e]]++;
}
}
for(int n = 0; n < size; n++) {
if(depth[n] == 0 && missing[n] <= 1) {
depth[n] = i;
root = n;
active = true;
}
}
if(!active) {
break;
}
Arrays.fill(missing, 0); // Clean up.
}
return root;
}
/**
* Parameterization class.
*
* @author Erich Schubert
*
* @apiviz.exclude
*/
public abstract static class Parameterizer extends AbstractParameterizer {
/**
* Similarity measure
*/
DimensionSimilarity sim;
@Override
protected void makeOptions(Parameterization config) {
super.makeOptions(config);
ObjectParameter> simP = new ObjectParameter<>(SIM_ID, DimensionSimilarity.class, CovarianceDimensionSimilarity.class);
if(config.grab(simP)) {
sim = simP.instantiateClass(config);
}
}
}
}
CompactCircularMSTLayout3DPC.java 0000664 0000000 0000000 00000011472 12657057427 0040511 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/dbs/elki/visualization/parallel3d/layout package de.lmu.ifi.dbs.elki.visualization.parallel3d.layout;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.List;
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.math.MathUtil;
import de.lmu.ifi.dbs.elki.math.dimensionsimilarity.DimensionSimilarity;
import de.lmu.ifi.dbs.elki.math.dimensionsimilarity.DimensionSimilarityMatrix;
import de.lmu.ifi.dbs.elki.utilities.documentation.Reference;
/**
* Simple circular layout based on the minimum spanning tree.
*
* Reference:
*
* Elke Achtert, Hans-Peter Kriegel, Erich Schubert, Arthur Zimek:
* Interactive Data Mining with 3D-Parallel-Coordinate-Trees.
* Proceedings of the 2013 ACM International Conference on Management of Data
* (SIGMOD), New York City, NY, 2013.
*
*
* @author Erich Schubert
* @since 0.6.0
*/
@Reference(authors = "Elke Achtert, Hans-Peter Kriegel, Erich Schubert, Arthur Zimek", title = "Interactive Data Mining with 3D-Parallel-Coordinate-Trees", booktitle = "Proc. of the 2013 ACM International Conference on Management of Data (SIGMOD)", url = "http://dx.doi.org/10.1145/2463676.2463696")
public class CompactCircularMSTLayout3DPC extends AbstractLayout3DPC {
/**
* Constructor.
*
* @param sim Similarity measure
*/
public CompactCircularMSTLayout3DPC(DimensionSimilarity sim) {
super(sim);
}
/**
* Node class for this layout.
*
* @author Erich Schubert
*/
public static class Node extends AbstractLayout3DPC.AbstractNode {
/**
* Weight (fanout needed)
*/
public int weight;
/**
* Constructor.
*
* @param dim Dimensionality
* @param children Number of children
*/
public Node(int dim, List children) {
super(dim, children);
}
}
@Override
public Layout layout(int dim, DimensionSimilarityMatrix mat) {
Layout l = new Layout();
Node rootnode = buildSpanningTree(mat, l);
int maxdepth = maxDepth(rootnode);
computeWeights(rootnode);
computePositions(rootnode, 0, 0, MathUtil.TWOPI, 0.0, 1.0 / (maxdepth - 1));
return l;
}
/**
* Recursively assign node weights.
*
* @param node Node to start with.
*/
private void computeWeights(Node node) {
int wsum = 0;
for (Node child : node.children) {
computeWeights(child);
wsum += child.weight;
}
node.weight = Math.max(1, wsum);
}
/**
* Compute the layout positions
*
* @param node Node to start with
* @param depth Depth of the node
* @param aoff Angular offset
* @param awid Angular width
* @param radius Current radius
* @param radiusinc Radius per depth step
*/
public static void computePositions(Node node, int depth, double aoff, double awid, double radius, double radiusinc) {
node.x = Math.sin(aoff) * radius;
node.y = Math.cos(aoff) * radius;
// Angular width per weight
double cwid = awid / node.weight;
// Avoid overly wide angles - shrink radius if necessary.
double div = 1;
if (node.weight > 1) {
double s = Math.sin(awid * .5), c = Math.cos(awid * .5);
double dx = s * (depth + 1), dy = c * (depth + 1) - depth;
double d = Math.sqrt(dx * dx + dy * dy) / MathUtil.SQRT2;
div = Math.max(div, d);
}
// Angular position of current child:
double cang = aoff - awid * .5 / div;
final double adjwid = cwid / div;
for (Node c : node.children) {
computePositions(c, depth + 1, cang + adjwid * c.weight * .5, adjwid * c.weight, radius + radiusinc, radiusinc);
cang += adjwid * c.weight;
}
}
@Override
Node makeNode(int dim, List children) {
return new Node(dim, children);
}
/**
* Parameteriation class.
*
* @author Erich Schubert
*
* @apiviz.exclude
*/
public static class Parameterizer extends AbstractLayout3DPC.Parameterizer {
@Override
protected CompactCircularMSTLayout3DPC makeInstance() {
return new CompactCircularMSTLayout3DPC(sim);
}
}
}
Layout.java 0000664 0000000 0000000 00000004667 12657057427 0034527 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/dbs/elki/visualization/parallel3d/layout package de.lmu.ifi.dbs.elki.visualization.parallel3d.layout;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.List;
/**
* Layout class.
*
* @author Erich Schubert
* @since 0.6.0
*/
public class Layout {
/**
* Edge class
*
* @author Erich Schubert
*/
public static class Edge {
/**
* The two dimensions connected by this edge.
*/
public int dim1, dim2;
/**
* Constructor.
*
* @param dim1 First dimension
* @param dim2 Second dimension
*/
public Edge(int dim1, int dim2) {
super();
this.dim1 = dim1;
this.dim2 = dim2;
}
}
/**
* Node of the layout tree.
*
* @author Erich Schubert
*/
public interface Node {
/**
* Get the dimension represented by this node.
*
* @return Dimension
*/
int getDim();
/**
* Get layout X position.
*
* @return X position
*/
double getX();
/**
* Get layout Y position.
*
* @return Y position
*/
double getY();
/**
* Get a child node.
*
* @param off offset
* @return Child node.
*/
Node getChild(int off);
/**
* Get the number of children.
*
* @return Number of children
*/
int numChildren();
}
/**
* Nodes
*/
public List extends Node> nodes;
/**
* Edges
*/
public List extends Edge> edges;
// TODO: add support for triangles.
/**
* Get the node for the given dimension.
*
* @param dim Dimension
* @return Node
*/
public Node getNode(int dim) {
return nodes.get(dim);
}
}
Layouter3DPC.java 0000664 0000000 0000000 00000002552 12657057427 0035457 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/dbs/elki/visualization/parallel3d/layout package de.lmu.ifi.dbs.elki.visualization.parallel3d.layout;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.database.relation.Relation;
/**
* Arrange parallel coordinates on a 2D plane, for 3D parallel coordinates.
*
* @author Erich Schubert
* @since 0.6.0
*
* @param Object type
*/
public interface Layouter3DPC {
/**
* Run the layouting algorithm.
*
* @param rel Relation to use
*
* @return Layout, nodes indexed by dimension.
*/
Layout layout(Relation extends V> rel);
}
MultidimensionalScalingMSTLayout3DPC.java 0000664 0000000 0000000 00000012060 12657057427 0042246 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/dbs/elki/visualization/parallel3d/layout package de.lmu.ifi.dbs.elki.visualization.parallel3d.layout;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.List;
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.math.dimensionsimilarity.DimensionSimilarity;
import de.lmu.ifi.dbs.elki.math.dimensionsimilarity.DimensionSimilarityMatrix;
import de.lmu.ifi.dbs.elki.math.linearalgebra.Matrix;
import de.lmu.ifi.dbs.elki.math.linearalgebra.SingularValueDecomposition;
import de.lmu.ifi.dbs.elki.utilities.documentation.Reference;
/**
* Layout the axes by multi-dimensional scaling.
*
* Reference:
*
* Elke Achtert, Hans-Peter Kriegel, Erich Schubert, Arthur Zimek:
* Interactive Data Mining with 3D-Parallel-Coordinate-Trees.
* Proceedings of the 2013 ACM International Conference on Management of Data
* (SIGMOD), New York City, NY, 2013.
*
*
* @author Erich Schubert
* @since 0.6.0
*/
@Reference(authors = "Elke Achtert, Hans-Peter Kriegel, Erich Schubert, Arthur Zimek", title = "Interactive Data Mining with 3D-Parallel-Coordinate-Trees", booktitle = "Proc. of the 2013 ACM International Conference on Management of Data (SIGMOD)", url = "http://dx.doi.org/10.1145/2463676.2463696")
public class MultidimensionalScalingMSTLayout3DPC extends AbstractLayout3DPC {
/**
* Constructor.
*
* @param sim Similarity measure
*/
public MultidimensionalScalingMSTLayout3DPC(DimensionSimilarity sim) {
super(sim);
}
/**
* Node class for this layout.
*
* @author Erich Schubert
*/
public static class Node extends AbstractLayout3DPC.AbstractNode {
/**
* Constructor.
*
* @param dim Dimensionality
* @param children Number of children
*/
public Node(int dim, List children) {
super(dim, children);
}
}
@Override
Node makeNode(int dim, List children) {
return new Node(dim, children);
}
@Override
public Layout layout(int dim, DimensionSimilarityMatrix mat) {
// Find maximum of |cij|
double max = 0;
for (int i = 0; i < dim; i++) {
for (int j = i + 1; j < dim; j++) {
double v = Math.abs(mat.get(j, i));
if (v > max) {
max = v;
}
}
}
// Assume that "max - |cij|" is now a distance.
// We use sqrt(v) instead of v*v, since this makes the method
// less aggressive overall, and we are not using euclidean anyway.
double means[] = new double[dim];
double mean = 0.0;
for (int i = 0; i < dim; i++) {
for (int j = i + 1; j < dim; j++) {
double v = max - Math.abs(mat.get(i, j));
v = -.5 * Math.sqrt(v);
means[i] += v;
means[j] += v;
mean += 2 * v;
}
}
for (int i = 0; i < dim; i++) {
means[i] /= dim;
}
mean /= (dim * dim);
// Build double centered matrix:
Matrix d = new Matrix(dim, dim);
for (int i = 0; i < dim; i++) {
d.set(i, i, -2 * means[i] + mean);
for (int j = i + 1; j < dim; j++) {
double v = max - Math.abs(mat.get(i, j));
v = -.5 * Math.sqrt(v) - means[i] - means[j] + mean;
d.set(i, j, v);
d.set(j, i, v);
}
}
SingularValueDecomposition svd = new SingularValueDecomposition(d);
Matrix u = svd.getU();
double[] lambda = svd.getSingularValues();
lambda[0] = Math.sqrt(Math.abs(lambda[0]));
lambda[1] = Math.sqrt(Math.abs(lambda[1]));
Layout l = new Layout();
buildSpanningTree(mat, l);
double maxabs = 0;
for (int i = 0; i < dim; i++) {
Node n = (Node) l.getNode(i);
n.x = u.get(i, 0) * lambda[0];
n.y = u.get(i, 1) * lambda[1];
double v = n.x * n.x + n.y * n.y;
if (v > maxabs) {
maxabs = v;
}
}
maxabs = 1. / Math.sqrt(maxabs);
for (int i = 0; i < dim; i++) {
Node n = (Node) l.getNode(i);
n.x *= maxabs;
n.y *= maxabs;
}
return l;
}
/**
* Parameteriation class.
*
* @author Erich Schubert
*
* @apiviz.exclude
*/
public static class Parameterizer extends AbstractLayout3DPC.Parameterizer {
@Override
protected MultidimensionalScalingMSTLayout3DPC makeInstance() {
return new MultidimensionalScalingMSTLayout3DPC(sim);
}
}
}
SimilarityBasedLayouter3DPC.java 0000664 0000000 0000000 00000003511 12657057427 0040461 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/dbs/elki/visualization/parallel3d/layout package de.lmu.ifi.dbs.elki.visualization.parallel3d.layout;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.math.dimensionsimilarity.DimensionSimilarity;
import de.lmu.ifi.dbs.elki.math.dimensionsimilarity.DimensionSimilarityMatrix;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID;
/**
* Similarity based layouting algorithms.
*
* @author Erich Schubert
* @since 0.6.0
*
* @param Data type
*/
public interface SimilarityBasedLayouter3DPC extends Layouter3DPC {
/**
* Option for similarity measure.
*/
public static final OptionID SIM_ID = new OptionID("parallel3d.sim", "Similarity measure for spanning tree.");
/**
* Get the similarity measure to use.
*
* @return Similarity measure.
*/
DimensionSimilarity super V> getSimilarity();
/**
* Main analysis method.
*
* @param dim Dimensionality
* @param mat Similarity matrix
* @return Layout
*/
Layout layout(final int dim, DimensionSimilarityMatrix mat);
}
SimpleCircularMSTLayout3DPC.java 0000664 0000000 0000000 00000010465 12657057427 0040355 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/dbs/elki/visualization/parallel3d/layout package de.lmu.ifi.dbs.elki.visualization.parallel3d.layout;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.List;
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.math.MathUtil;
import de.lmu.ifi.dbs.elki.math.dimensionsimilarity.DimensionSimilarity;
import de.lmu.ifi.dbs.elki.math.dimensionsimilarity.DimensionSimilarityMatrix;
import de.lmu.ifi.dbs.elki.utilities.documentation.Reference;
/**
* Simple circular layout based on the minimum spanning tree.
*
* Reference:
*
* Elke Achtert, Hans-Peter Kriegel, Erich Schubert, Arthur Zimek:
* Interactive Data Mining with 3D-Parallel-Coordinate-Trees.
* Proceedings of the 2013 ACM International Conference on Management of Data
* (SIGMOD), New York City, NY, 2013.
*
*
* @author Erich Schubert
* @since 0.6.0
*/
@Reference(authors = "Elke Achtert, Hans-Peter Kriegel, Erich Schubert, Arthur Zimek", title = "Interactive Data Mining with 3D-Parallel-Coordinate-Trees", booktitle = "Proc. of the 2013 ACM International Conference on Management of Data (SIGMOD)", url = "http://dx.doi.org/10.1145/2463676.2463696")
public class SimpleCircularMSTLayout3DPC extends AbstractLayout3DPC {
/**
* Constructor.
*
* @param sim Similarity measure
*/
public SimpleCircularMSTLayout3DPC(DimensionSimilarity sim) {
super(sim);
}
/**
* Node class for this layout.
*
* @author Erich Schubert
*/
public static class Node extends AbstractLayout3DPC.AbstractNode {
/**
* Weight (fanout needed)
*/
public int weight;
/**
* Constructor.
*
* @param dim Dimensionality
* @param children Number of children
*/
public Node(int dim, List children) {
super(dim, children);
}
}
@Override
public Layout layout(int dim, DimensionSimilarityMatrix mat) {
Layout l = new Layout();
Node rootnode = buildSpanningTree(mat, l);
int maxdepth = maxDepth(rootnode);
computeWeights(rootnode);
computePositions(rootnode, 0, 0, MathUtil.TWOPI, maxdepth);
return l;
}
/**
* Recursively assign node weights.
*
* @param node Node to start with.
*/
private void computeWeights(Node node) {
int wsum = 0;
for (Node child : node.children) {
computeWeights(child);
wsum += child.weight;
}
node.weight = Math.max(1, wsum);
}
/**
* Compute the layout positions
*
* @param node Node to start with
* @param depth Depth of the node
* @param aoff Angular offset
* @param awid Angular width
* @param maxdepth Maximum depth (used for radius computations)
*/
public static void computePositions(Node node, int depth, double aoff, double awid, int maxdepth) {
double r = depth / (maxdepth - 1.);
node.x = Math.sin(aoff + awid * .5) * r;
node.y = Math.cos(aoff + awid * .5) * r;
double cpos = aoff;
double cwid = awid / node.weight;
for (Node c : node.children) {
computePositions(c, depth + 1, cpos, cwid * c.weight, maxdepth);
cpos += cwid * c.weight;
}
}
@Override
Node makeNode(int dim, List children) {
return new Node(dim, children);
}
/**
* Parameteriation class.
*
* @author Erich Schubert
*
* @apiviz.exclude
*/
public static class Parameterizer extends AbstractLayout3DPC.Parameterizer {
@Override
protected SimpleCircularMSTLayout3DPC makeInstance() {
return new SimpleCircularMSTLayout3DPC(sim);
}
}
}
package-info.java 0000664 0000000 0000000 00000002030 12657057427 0035554 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/dbs/elki/visualization/parallel3d/layout /**
* Layouting algorithms for 3D parallel coordinate plots.
*
* @author Erich Schubert
*/
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.lmu.ifi.dbs.elki.visualization.parallel3d.layout; package-info.java 0000664 0000000 0000000 00000002700 12657057427 0034243 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/dbs/elki/visualization/parallel3d /**
* 3DPC: 3D parallel coordinate plot visualization for ELKI.
*
* This is an add-on module. Details were published as:
*
* Reference:
*
* Elke Achtert, Hans-Peter Kriegel, Erich Schubert, Arthur Zimek:
* Interactive Data Mining with 3D-Parallel-Coordinate-Trees.
* Proceedings of the 2013 ACM International Conference on Management of Data (SIGMOD), New York City, NY, 2013.
*
*
* For further information, visit also: http://elki.dbs.ifi.lmu.de/wiki/3DPC
*
* @author Erich Schubert
*/
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.lmu.ifi.dbs.elki.visualization.parallel3d; elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/dbs/elki/visualization/parallel3d/util/ 0000775 0000000 0000000 00000000000 12657057427 0032111 5 ustar 00root root 0000000 0000000 AbstractSimpleOverlay.java 0000664 0000000 0000000 00000004400 12657057427 0037152 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/dbs/elki/visualization/parallel3d/util package de.lmu.ifi.dbs.elki.visualization.parallel3d.util;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import javax.media.opengl.GL2;
/**
* Renderer for simple overlays.
*
* TODO: make color configurable?
*
* @author Erich Schubert
* @since 0.6.0
*/
public abstract class AbstractSimpleOverlay {
/**
* Screen ratio.
*/
int width = 100;
/**
* Screen ratio.
*/
int height = 100;
/**
* Main render method
*
* @param gl GL context
*/
public final void render(GL2 gl) {
gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glPushMatrix();
gl.glLoadIdentity();
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glPushMatrix();
gl.glLoadIdentity();
gl.glOrtho(0, width, 0, height, -1, +1);
gl.glColor4f(0f, 0f, 0f, .5f);
// Fade background:
gl.glBegin(GL2.GL_QUADS);
gl.glVertex2f(0f, 0f);
gl.glVertex2f(width, 0f);
gl.glVertex2f(width, height);
gl.glVertex2f(0f, height);
gl.glEnd();
renderContents(gl);
gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glPopMatrix();
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glPopMatrix();
}
/**
* Render the actual overlay contents.
*
* @param gl GL context
*/
abstract void renderContents(GL2 gl);
/**
* Set screen ratio.
*
* @param width Screen width
* @param height Screen height
*/
public void setSize(int width, int height) {
this.width = width;
this.height = height;
}
}
Arcball1DOFAdapter.java 0000664 0000000 0000000 00000010570 12657057427 0036153 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/dbs/elki/visualization/parallel3d/util package de.lmu.ifi.dbs.elki.visualization.parallel3d.util;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.swing.event.MouseInputAdapter;
import de.lmu.ifi.dbs.elki.math.linearalgebra.VMath;
/**
* Arcball style helper.
*
* @author Erich Schubert
* @since 0.6.0
*
* @apiviz.uses Simple1DOFCamera
*/
public class Arcball1DOFAdapter extends MouseInputAdapter {
/**
* Debug flag.
*/
private static final boolean DEBUG = false;
/**
* The true camera.
*/
private final Simple1DOFCamera camera;
/**
* Starting point of drag.
*/
private double[] startvec = new double[3];
/**
* Ending point of drag.
*/
private double[] endvec = new double[3];
/**
* Temp buffer we use for computations.
*/
private double[] near = new double[3], far = new double[3];
/**
* Starting angle for dragging.
*/
double startangle;
/**
* Camera that was in use when the drag started.
*/
private Simple1DOFCamera startcamera;
/**
* Constructor.
*
* @param camera Scene camera
*/
public Arcball1DOFAdapter(Simple1DOFCamera camera) {
super();
this.camera = camera;
}
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
int s = e.getWheelRotation();
double distance = camera.getDistance();
for (; s >= 1; s--) {
distance += .1;
}
for (; s <= -1; s++) {
if (distance > .15) {
distance -= .1;
}
}
camera.setDistance(distance);
}
@Override
public void mousePressed(MouseEvent e) {
// Start drag.
startcamera = new Simple1DOFCamera(camera);
Point startPoint = e.getPoint();
mapMouseToPlane(startcamera, startPoint, startvec);
startangle = Math.atan2(startvec[1], startvec[0]);
}
/**
* Map the coordinates. Note: vec will be overwritten!
*
* @param camera Camera
* @param point2d Input point
* @param vec Output vector
*/
private void mapMouseToPlane(Simple1DOFCamera camera, Point point2d, double[] vec) {
// Far plane
camera.unproject(point2d.x, point2d.y, -100., far);
// Near plane
camera.unproject(point2d.x, point2d.y, 1., near);
// Delta vector: far -= near.
VMath.minusEquals(far, near);
// Intersection with z=0 plane:
// far.z - a * near.z = 0 -> a = far.z / near.z
if (near[2] < 0 || near[2] > 0) {
double a = far[2] / near[2];
vec[0] = far[0] - a * near[0];
vec[1] = far[1] - a * near[1];
vec[2] = 0;
}
}
@Override
public void mouseDragged(MouseEvent e) {
mapMouseToPlane(startcamera, e.getPoint(), endvec);
double upangle = Math.atan2(endvec[1], endvec[0]);
camera.setRotationZ(startcamera.getRotationZ() + (upangle - startangle));
// TODO: add full arcball support?
}
/**
* Render a debugging hint for the arcball tool.
*
* @param gl GL class for rendering-
*/
@SuppressWarnings("unused")
public void debugRender(GL2 gl) {
if (!DEBUG || (startcamera == null)) {
return;
}
gl.glLineWidth(3f);
gl.glColor4f(1.f, 0.f, 0.f, .66f);
gl.glBegin(GL.GL_LINES);
gl.glVertex3f(0.f, 0.f, 0.f);
double rot = startangle - startcamera.getRotationZ();
gl.glVertex3f((float) Math.cos(rot) * 4.f, (float) -Math.sin(rot) * 4.f, 0.f);
gl.glVertex3f((float) Math.cos(rot) * 1.f, (float) -Math.sin(rot) * 1.f, 0.f);
gl.glVertex3f((float) Math.cos(rot) * 1.f, (float) -Math.sin(rot) * 1.f, 1.f);
gl.glEnd();
}
} Simple1DOFCamera.java 0000664 0000000 0000000 00000017014 12657057427 0035654 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/dbs/elki/visualization/parallel3d/util package de.lmu.ifi.dbs.elki.visualization.parallel3d.util;
import java.util.ArrayList;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.fixedfunc.GLMatrixFunc;
import javax.media.opengl.glu.GLU;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
/**
* Class for a simple camera. Restricted: always looks at 0,0,0 from a position
* defined by rotationX, distance and height.
*
* For rotationX = 0, the camera will be at y=distance, x=0, so that the default
* view will have the usual X/Y plane on the ground.
*
* @author Erich Schubert
* @since 0.6.0
*
* @apiviz.uses CameraListener
*/
public class Simple1DOFCamera {
/**
* Rotation on X axis.
*/
private double rotationZ = 0.;
/**
* Distance
*/
private double distance = 3;
/**
* Height
*/
private double height = 1.5;
/**
* Screen ratio
*/
private double ratio = 1.0;
/**
* GLU viewport storage
*/
private int[] viewp = new int[4];
/**
* GLU model view matrix
*/
private double[] modelview = new double[16];
/**
* GLU projection matrix
*/
private double[] projection = new double[16];
/**
* GLU utility
*/
private GLU glu;
/**
* Cache the Z rotation cosine
*/
private double cosZ;
/**
* Cache the Z rotation sine
*/
private double sinZ;
/**
* Camera listener list.
*/
ArrayList listeners;
/**
* Constructor.
*
* @param glu GLU utility class
*/
public Simple1DOFCamera(GLU glu) {
super();
this.glu = glu;
viewp = new int[4];
modelview = new double[16];
projection = new double[16];
// Initial angle:
rotationZ = 0;
cosZ = 1.0;
sinZ = 0.0;
listeners = new ArrayList<>(5);
}
/**
* Copy constructor, for freezing a camera position.
*
* Note: listeners will not be copied.
*
* @param other Existing camera
*/
public Simple1DOFCamera(Simple1DOFCamera other) {
super();
this.rotationZ = other.rotationZ;
this.distance = other.distance;
this.height = other.height;
this.ratio = other.ratio;
this.viewp = other.viewp.clone();
this.modelview = other.modelview.clone();
this.projection = other.projection.clone();
this.glu = other.glu;
this.listeners = null; // Do NOT copy listeners
}
/**
* Get the distance
*
* @return Distance
*/
public double getDistance() {
return distance;
}
/**
* Set camera distance
*
* @param distance Distance
*/
public void setDistance(double distance) {
this.distance = distance;
fireCameraChangedEvent();
}
/**
* Get camera height
*
* @return Camera height
*/
public double getHeight() {
return height;
}
/**
* Set camera height
*
* @param height Camera height
*/
public void setHeight(double height) {
this.height = height;
fireCameraChangedEvent();
}
/**
* Get screen ratio.
*
* @return Screen ratio
*/
public double getRatio() {
return ratio;
}
/**
* Set screen ratio.
*
* @param ratio Screen ratio
*/
public void setRatio(double ratio) {
this.ratio = ratio;
// As this will be triggered by the canvas only,
// Do not fire an event.
}
/**
* Get the Z rotation in radians.
*
* @return Z rotation angle (radians)
*/
public double getRotationZ() {
return rotationZ;
}
/**
* Set the z rotation angle in radians.
*
* @param rotationZ Z rotation angle.
*/
public void setRotationZ(double rotationZ) {
this.rotationZ = rotationZ;
this.cosZ = Math.cos(rotationZ);
this.sinZ = Math.sin(rotationZ);
fireCameraChangedEvent();
}
/**
* Apply the camera to a GL context.
*
* @param gl GL context.
*/
public void apply(GL2 gl) {
// 3D projection
gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glLoadIdentity();
// Perspective.
glu.gluPerspective(35, ratio, 1, 1000);
glu.gluLookAt(distance * sinZ, distance * -cosZ, height, // pos
0, 0, .5, // center
0, 0, 1 // up
);
// Change back to model view matrix.
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glLoadIdentity();
// Store the matrixes for reference.
gl.glGetIntegerv(GL.GL_VIEWPORT, viewp, 0);
gl.glGetDoublev(GLMatrixFunc.GL_MODELVIEW_MATRIX, modelview, 0);
gl.glGetDoublev(GLMatrixFunc.GL_PROJECTION_MATRIX, projection, 0);
}
/**
* Unproject a screen coordinate (at depth 0) to 3D model coordinates.
*
* @param x X
* @param y Y
* @return model coordinates
*/
public double[] unproject(double x, double y, double z) {
double[] out = new double[3];
unproject(x, y, z, out);
return out;
}
/**
* Unproject a screen coordinate (at depth 0) to 3D model coordinates.
*
* @param x X
* @param y Y
* @param Out output buffer
*/
public void unproject(double x, double y, double z, double[] out) {
glu.gluUnProject(x, y, z, modelview, 0, projection, 0, viewp, 0, out, 0);
}
/**
* Project a coordinate
*
* @param vec Input vector buffer
* @param Out output buffer
*/
public void project(double x, double y, double z, double[] out) {
glu.gluProject(x, y, z, modelview, 0, projection, 0, viewp, 0, out, 0);
}
/**
* Distance from camera
*
* @param x X position
* @param y Y position
* @return Squared distance
*/
public double squaredDistanceFromCamera(double x, double y) {
double dx = (distance * sinZ) - x;
double dy = (distance * -cosZ) - y;
return dx * dx + dy * dy;
}
/**
* Distance from camera
*
* @param x X position
* @param y Y position
* @param z Z position
* @return Squared distance
*/
public double squaredDistanceFromCamera(double x, double y, double z) {
double dx = (distance * sinZ) - x;
double dy = (distance * -cosZ) - y;
double dz = height - z;
return dx * dx + dy * dy + dz * dz;
}
/**
* Add a camera listener.
*
* @param lis Listener
*/
public void addCameraListener(CameraListener lis) {
if (listeners == null) {
listeners = new ArrayList<>(5);
}
listeners.add(lis);
}
/**
* Remove a camera listener.
*
* @param lis Listener
*/
public void removeCameraListener(CameraListener lis) {
if (listeners == null) {
return;
}
listeners.remove(lis);
}
/**
* Fire the camera changed event.
*/
protected void fireCameraChangedEvent() {
if (listeners != null) {
for (CameraListener list : listeners) {
list.cameraChanged();
}
}
}
/**
* Camera Listener class
*
* @author Erich Schubert
*/
public static interface CameraListener {
/**
* Camera changed.
*/
public void cameraChanged();
}
}
SimpleMenuOverlay.java 0000664 0000000 0000000 00000013074 12657057427 0036322 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/dbs/elki/visualization/parallel3d/util package de.lmu.ifi.dbs.elki.visualization.parallel3d.util;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.awt.Font;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import javax.media.opengl.GL2;
import com.jogamp.opengl.util.awt.TextRenderer;
/**
* Simple menu overlay.
*
* TODO: Hover effects?
*
* @author Erich Schubert
* @since 0.6.0
*/
public abstract class SimpleMenuOverlay extends AbstractSimpleOverlay implements MouseListener {
/**
* Text renderer
*/
TextRenderer renderer;
/**
* Options to display.
*/
private ArrayList options = new ArrayList<>();
/**
* Font size.
*/
int fontsize;
/**
* Constructor.
*/
public SimpleMenuOverlay() {
super();
fontsize = 18;
renderer = new TextRenderer(new Font(Font.SANS_SERIF, Font.PLAIN, fontsize));
}
@Override
void renderContents(GL2 gl) {
final int numopt = getOptions().size();
double maxwidth = 0.;
Rectangle2D[] bounds = new Rectangle2D[numopt];
for (int i = 0; i < numopt; i++) {
final String string = getOptions().get(i);
if (string != null) {
bounds[i] = renderer.getBounds(string);
maxwidth = Math.max(bounds[i].getWidth(), maxwidth);
}
}
final double padding = .5 * fontsize;
final double margin = padding * .3;
final float bx1 = (float) (.5 * (width - maxwidth - padding));
final float bx2 = (float) (.5 * (width + maxwidth + padding));
double totalheight = numopt * fontsize + (numopt - 1) * padding;
// Render background buttons:
gl.glBegin(GL2.GL_QUADS);
gl.glColor4f(0f, 0f, 0f, .75f);
for (int i = 0; i < numopt; i++) {
if (bounds[numopt - i - 1] == null) {
continue;
}
final double pos = (height - totalheight) * .5 + fontsize * i + padding * i;
// Render a background button:
gl.glVertex2f(bx1, (float) (pos - margin));
gl.glVertex2f(bx1, (float) (pos + fontsize + margin));
gl.glVertex2f(bx2, (float) (pos + fontsize + margin));
gl.glVertex2f(bx2, (float) (pos - margin));
}
gl.glEnd();
// Render text labels:
renderer.beginRendering(width, height);
renderer.setColor(1f, 1f, 1f, 1f);
// NOTE: renderer uses (0,0) as BOTTOM left!
for (int j = 0; j < numopt; j++) {
if (bounds[j] == null) {
continue;
}
final int i = numopt - j - 1;
// Extra offset .17 * fontsize because of text baseline!
final double pos = (height - totalheight) * .5 + fontsize * i + padding * i + .17 * fontsize;
renderer.setColor(1f, 1f, 1f, 1f);
renderer.draw(getOptions().get(j), (width - (int) bounds[j].getWidth()) >> 1, (int) pos);
}
renderer.endRendering();
}
@Override
public void mouseClicked(MouseEvent e) {
// close with right mouse button:
if (e.getButton() == MouseEvent.BUTTON3) {
menuItemClicked(-1);
}
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
final int mx = e.getX(), my = e.getY();
final int numopt = getOptions().size();
double maxwidth = 0.;
for (int i = 0; i < numopt; i++) {
final String string = getOptions().get(i);
if (string != null) {
Rectangle2D bounds = renderer.getBounds(string);
maxwidth = Math.max(bounds.getWidth(), maxwidth);
}
}
final double padding = .5 * fontsize;
final double margin = padding * .3;
final float bx1 = (float) (.5 * (width - maxwidth - padding));
final float bx2 = (float) (.5 * (width + maxwidth + padding));
if (mx < bx1 || mx > bx2) {
menuItemClicked(-1);
return;
}
double totalheight = numopt * fontsize + (numopt - 1) * padding;
for (int i = 0; i < numopt; i++) {
final double pos = (height - totalheight) * .5 + fontsize * i + padding * i;
if (my < pos - margin) {
menuItemClicked(-1);
return;
}
if (my < pos + fontsize + margin) {
menuItemClicked(i);
return;
}
}
// Otherwise, close.
menuItemClicked(-1);
}
/**
* Callback when a menu item was clicked.
*
* @param item Item number that was clicked.
*/
public abstract void menuItemClicked(int item);
@Override
public void mousePressed(MouseEvent e) {
// Ignore
}
@Override
public void mouseReleased(MouseEvent e) {
// Ignore
}
@Override
public void mouseEntered(MouseEvent e) {
// Ignore
}
@Override
public void mouseExited(MouseEvent e) {
// Ignore
}
/**
* @return the options
*/
public ArrayList getOptions() {
return options;
}
/**
* @param options the options to set
*/
public void setOptions(ArrayList options) {
this.options = options;
}
}
SimpleMessageOverlay.java 0000664 0000000 0000000 00000005253 12657057427 0037002 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/dbs/elki/visualization/parallel3d/util package de.lmu.ifi.dbs.elki.visualization.parallel3d.util;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.awt.Font;
import java.awt.geom.Rectangle2D;
import javax.media.opengl.GL2;
import com.jogamp.opengl.util.awt.TextRenderer;
/**
* Simple menu overlay.
*
* @author Erich Schubert
* @since 0.6.0
*/
public class SimpleMessageOverlay extends AbstractSimpleOverlay {
/**
* Text renderer
*/
TextRenderer renderer;
/**
* Message to display.
*/
private String message = "";
/**
* Font size.
*/
int fontsize;
/**
* Constructor.
*/
public SimpleMessageOverlay() {
super();
fontsize = 18;
renderer = new TextRenderer(new Font(Font.SANS_SERIF, Font.PLAIN, fontsize));
}
@Override
void renderContents(GL2 gl) {
// Get text bounds.
Rectangle2D bounds = renderer.getBounds(getMessage());
// Render message background:
final float bx1 = .45f * (float) (width - bounds.getWidth());
final float bx2 = .55f * (float) (width + bounds.getWidth());
final float by1 = .45f * (float) (height - bounds.getHeight());
final float by2 = .55f * (float) (height + bounds.getHeight());
gl.glBegin(GL2.GL_QUADS);
gl.glColor4f(0f, 0f, 0f, .75f);
gl.glVertex2f(bx1, by1);
gl.glVertex2f(bx1, by2);
gl.glVertex2f(bx2, by2);
gl.glVertex2f(bx2, by1);
gl.glEnd();
// Render message
renderer.beginRendering(width, height);
renderer.setColor(1f, 1f, 1f, 1f);
renderer.setColor(1f, 1f, 1f, 1f);
renderer.draw(getMessage(), (width - (int) bounds.getWidth()) >> 1, (height - (int) bounds.getHeight()) >> 1);
renderer.endRendering();
}
/**
* @return the message
*/
public String getMessage() {
return message;
}
/**
* @param message the message to set
*/
public void setMessage(String message) {
this.message = message;
}
}
package-info.java 0000664 0000000 0000000 00000002020 12657057427 0035213 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/java/de/lmu/ifi/dbs/elki/visualization/parallel3d/util /**
* Utility classes (primarily rendering utilities).
*
* @author Erich Schubert
*/
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.lmu.ifi.dbs.elki.visualization.parallel3d.util; elki-release0.7.1/addons/3dpc/src/main/resources/ 0000775 0000000 0000000 00000000000 12657057427 0021651 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/resources/3dpc.CMD 0000664 0000000 0000000 00000002124 12657057427 0023026 0 ustar 00root root 0000000 0000000 @ECHO OFF
REM Windows batch file for running ELKI with 3DPC add-on.
REM You will need the following files:
REM elki.jar, 3dpc.jar, JOGL2 jars (gluegen-rt, jogl-all, natives)
REM
REM You can put them into the same folder, or into a "lib" directory
REM Build classpath
SETLOCAL enabledelayedexpansion
SET CP=
FOR %%F IN ("*.jar" "lib\*.jar") DO (
SET CP=!CP!;%%F%
)
REM Locate Java. Honor JAVA_HOME variable
IF DEFINED JAVA_HOME (
SET JAVA="%JAVA_HOME%\bin\java.exe"
)
REM Try in windows path
IF "%JAVA%" == "" (
FOR /f %%j IN ("java.exe") DO (
SET JAVA=%%~dpn$PATH:j
)
)
REM Guess typical installation directories for java 7.
IF "%JAVA%" == "" (
FOR /d %%i IN ("%ProgramFiles%\Java\jdk7*" "%ProgramFiles%\Java\jre7*" "%ProgramFiles%(x86)\Java\jdk7*" "%ProgramFiles(x86)%\Java\jre7*") DO (
SET JAVA=%%i\bin\java.exe
)
)
REM Fail if still no java found
IF "%JAVA%" == "" (
ECHO CANNOT LOCATE JAVA. Try setting JAVA_HOME, or modify the
ECHO Launcher script with your path.
PAUSE
EXIT
)
REM Launch ELKI:
"%JAVA%" -Xmx1G ^
-cp "%CP%" ^
de.lmu.ifi.dbs.elki.application.ELKILauncher
elki-release0.7.1/addons/3dpc/src/main/resources/LICENSE.txt 0000664 0000000 0000000 00000106045 12657057427 0023502 0 ustar 00root root 0000000 0000000 ELKI: Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2013 Lehr- und Forschungseinheit für Datenbanksysteme, Ludwig-Maximilians-Universität München
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
You can contact the authors at:
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
Oettingenstraße 67
80538 München
GERMANY
or via email at elki@dbs.ifi.lmu.de
Disclaimer:
This license applies only to the software developed by the authors named above
in the "de.lmu.ifi.dbs.elki" Java namespace. You could have received this code
as part of a bundle that also contains code by other authors where other
license terms apply, and it is up to you to verify this is the correct file.
---
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
. elki-release0.7.1/addons/3dpc/src/main/resources/META-INF/ 0000775 0000000 0000000 00000000000 12657057427 0023011 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/resources/META-INF/elki/ 0000775 0000000 0000000 00000000000 12657057427 0023735 5 ustar 00root root 0000000 0000000 de.lmu.ifi.dbs.elki.result.ResultHandler 0000664 0000000 0000000 00000000111 12657057427 0033306 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/resources/META-INF/elki de.lmu.ifi.dbs.elki.visualization.parallel3d.OpenGL3DParallelCoordinates
de.lmu.ifi.dbs.elki.visualization.parallel3d.layout.Layouter3DPC 0000664 0000000 0000000 00000000372 12657057427 0037702 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/3dpc/src/main/resources/META-INF/elki de.lmu.ifi.dbs.elki.visualization.parallel3d.layout.SimpleCircularMSTLayout3DPC
de.lmu.ifi.dbs.elki.visualization.parallel3d.layout.CompactCircularMSTLayout3DPC
de.lmu.ifi.dbs.elki.visualization.parallel3d.layout.MultidimensionalScalingMSTLayout3DPC
elki-release0.7.1/addons/batikvis/ 0000775 0000000 0000000 00000000000 12657057427 0017107 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/.classpath 0000664 0000000 0000000 00000002253 12657057427 0021074 0 ustar 00root root 0000000 0000000
elki-release0.7.1/addons/batikvis/.gitignore 0000664 0000000 0000000 00000000011 12657057427 0021067 0 ustar 00root root 0000000 0000000 /target/
elki-release0.7.1/addons/batikvis/.project 0000664 0000000 0000000 00000001051 12657057427 0020553 0 ustar 00root root 0000000 0000000
elki-batik-visualizationorg.eclipse.jdt.core.javabuilderorg.eclipse.m2e.core.maven2Builderorg.eclipse.jdt.core.javanatureorg.eclipse.m2e.core.maven2Nature
elki-release0.7.1/addons/batikvis/.settings/ 0000775 0000000 0000000 00000000000 12657057427 0021025 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/.settings/org.eclipse.core.resources.prefs 0000664 0000000 0000000 00000000170 12657057427 0027236 0 ustar 00root root 0000000 0000000 eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/main/resources=UTF-8
encoding/=UTF-8
elki-release0.7.1/addons/batikvis/.settings/org.eclipse.jdt.core.prefs 0000664 0000000 0000000 00000056763 12657057427 0026030 0 ustar 00root root 0000000 0000000 eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.7
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=0
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=0
org.eclipse.jdt.core.formatter.alignment_for_compact_if=0
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=0
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=0
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=0
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
org.eclipse.jdt.core.formatter.blank_lines_before_field=1
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
org.eclipse.jdt.core.formatter.comment.format_header=false
org.eclipse.jdt.core.formatter.comment.format_html=true
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
org.eclipse.jdt.core.formatter.comment.format_source_code=true
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
org.eclipse.jdt.core.formatter.comment.line_length=80
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
org.eclipse.jdt.core.formatter.compact_else_if=true
org.eclipse.jdt.core.formatter.continuation_indentation=2
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_empty_lines=false
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
org.eclipse.jdt.core.formatter.indentation.size=2
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
org.eclipse.jdt.core.formatter.lineSplit=80
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
org.eclipse.jdt.core.formatter.tabulation.char=space
org.eclipse.jdt.core.formatter.tabulation.size=2
org.eclipse.jdt.core.formatter.use_on_off_tags=false
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
elki-release0.7.1/addons/batikvis/.settings/org.eclipse.jdt.ui.prefs 0000664 0000000 0000000 00000013670 12657057427 0025503 0 ustar 00root root 0000000 0000000 eclipse.preferences.version=1
formatter_profile=_ELKI
formatter_settings_version=12
org.eclipse.jdt.ui.javadoc=false
org.eclipse.jdt.ui.text.custom_code_templates=/**\n * @return the ${bare_field_name}\n *//**\n * @param ${param} the ${bare_field_name} to set\n *//**\n * Constructor.\n *\n * ${tags}\n *//**\n * @author ${user}\n *\n * ${tags}\n *//**\n * \n *//**\n * ${tags}\n *//**\n * ${tags}\n * ${see_to_target}\n */${filecomment}\n${package_declaration}\n/*\n This file is part of ELKI\:\n Environment for Developing KDD-Applications Supported by Index-Structures\n\n Copyright (C) ${year}\n Ludwig-Maximilians-Universit\u00E4t M\u00FCnchen\n Lehr- und Forschungseinheit f\u00FCr Datenbanksysteme\n ELKI Development Team\n\n This program is free software\: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http\://www.gnu.org/licenses/>.\n */\n\n${typecomment}\n${type_declaration}\n\n\n\n// ${todo} Auto-generated catch block\nde.lmu.ifi.dbs.elki.logging.LoggingUtil.exception(${exception_var});// ${todo} Auto-generated method stub\n${body_statement}${body_statement}\n// ${todo} Auto-generated constructor stubreturn ${field};${field} \= ${param};
elki-release0.7.1/addons/batikvis/.settings/org.eclipse.m2e.core.prefs 0000664 0000000 0000000 00000000126 12657057427 0025710 0 ustar 00root root 0000000 0000000 activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1
elki-release0.7.1/addons/batikvis/pom.xml 0000664 0000000 0000000 00000010040 12657057427 0020417 0 ustar 00root root 0000000 0000000
4.0.0de.lmu.ifi.dbs.elki0.7.1elki-project../../elki-batik-visualizationjarELKI Data Mining Framework - Batik VisualizationGNU Affero General Public License (AGPL) version 3.0http://www.gnu.org/licenses/agpl-3.0.txt${basedir}/../..maven-jar-plugin${elki.projdir}/elki/src/main/resources/META-INF/MANIFEST.MFtruede.lmu.ifi.dbs.elki.application.ELKILauncherdependency/maven-antrun-plugincreateJavadocDirprepare-packagerunorg.codehaus.mojoexec-maven-plugingenerate-javadoc-parametersprepare-packageexecjava-cpde.lmu.ifi.dbs.elki.application.internal.DocumentParameters${project.build.directory}/apidocs/parameters-byclass-vis.html${project.build.directory}/apidocs/parameters-byopt-vis.htmlgenerate-javadoc-referencesprepare-packageexecjava-cpde.lmu.ifi.dbs.elki.application.internal.DocumentReferences${project.build.directory}/apidocs/references-vis.html${project.build.directory}/apidocs/references-vis.tracnet.sf.trove4jtrove4jorg.apache.xmlgraphicsbatik-swingorg.apache.xmlgraphicsbatik-rasterizerorg.apache.xmlgraphicsbatik-extorg.apache.xmlgraphicsbatik-codecorg.apache.xmlgraphicsxmlgraphics-commonsde.lmu.ifi.dbs.elkielki${project.version}
elki-release0.7.1/addons/batikvis/src/ 0000775 0000000 0000000 00000000000 12657057427 0017676 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/ 0000775 0000000 0000000 00000000000 12657057427 0020622 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/ 0000775 0000000 0000000 00000000000 12657057427 0021543 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/ 0000775 0000000 0000000 00000000000 12657057427 0022133 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ 0000775 0000000 0000000 00000000000 12657057427 0022730 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/ 0000775 0000000 0000000 00000000000 12657057427 0023477 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/ 0000775 0000000 0000000 00000000000 12657057427 0024247 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/ 0000775 0000000 0000000 00000000000 12657057427 0025173 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/application/ 0000775 0000000 0000000 00000000000 12657057427 0027476 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/application/greedyensemble/ 0000775 0000000 0000000 00000000000 12657057427 0032470 5 ustar 00root root 0000000 0000000 VisualizePairwiseGainMatrix.java 0000664 0000000 0000000 00000031243 12657057427 0040722 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/application/greedyensemble package de.lmu.ifi.dbs.elki.application.greedyensemble;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.awt.image.BufferedImage;
import org.apache.batik.util.SVGConstants;
import de.lmu.ifi.dbs.elki.application.AbstractApplication;
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.data.type.TypeUtil;
import de.lmu.ifi.dbs.elki.database.Database;
import de.lmu.ifi.dbs.elki.database.ids.ArrayModifiableDBIDs;
import de.lmu.ifi.dbs.elki.database.ids.DBID;
import de.lmu.ifi.dbs.elki.database.ids.DBIDArrayIter;
import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil;
import de.lmu.ifi.dbs.elki.database.relation.Relation;
import de.lmu.ifi.dbs.elki.database.relation.RelationUtil;
import de.lmu.ifi.dbs.elki.evaluation.scores.ROCEvaluation;
import de.lmu.ifi.dbs.elki.evaluation.scores.adapter.DecreasingVectorIter;
import de.lmu.ifi.dbs.elki.evaluation.scores.adapter.VectorNonZero;
import de.lmu.ifi.dbs.elki.evaluation.similaritymatrix.ComputeSimilarityMatrixImage;
import de.lmu.ifi.dbs.elki.evaluation.similaritymatrix.ComputeSimilarityMatrixImage.SimilarityMatrix;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.logging.progress.FiniteProgress;
import de.lmu.ifi.dbs.elki.math.DoubleMinMax;
import de.lmu.ifi.dbs.elki.math.linearalgebra.Vector;
import de.lmu.ifi.dbs.elki.result.ResultHierarchy;
import de.lmu.ifi.dbs.elki.utilities.DatabaseUtil;
import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.Hierarchy;
import de.lmu.ifi.dbs.elki.utilities.documentation.Reference;
import de.lmu.ifi.dbs.elki.utilities.ensemble.EnsembleVoting;
import de.lmu.ifi.dbs.elki.utilities.ensemble.EnsembleVotingMean;
import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ObjectParameter;
import de.lmu.ifi.dbs.elki.utilities.scaling.LinearScaling;
import de.lmu.ifi.dbs.elki.utilities.scaling.ScalingFunction;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTree;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.VisualizerParameterizer;
import de.lmu.ifi.dbs.elki.visualization.gui.SimpleSVGViewer;
import de.lmu.ifi.dbs.elki.visualization.gui.VisualizationPlot;
import de.lmu.ifi.dbs.elki.visualization.visualizers.Visualization;
import de.lmu.ifi.dbs.elki.visualization.visualizers.visunproj.SimilarityMatrixVisualizer;
import de.lmu.ifi.dbs.elki.workflow.InputStep;
/**
* Class to load an outlier detection summary file, as produced by
* {@link ComputeKNNOutlierScores}, and compute a matrix with the pairwise
* gains. It will have one column / row obtained for each combination.
*
* The gain is always computed in relation to the better of the two input
* methods. Green colors indicate the result has improved, red indicate it
* became worse.
*
* Reference:
*
* E. Schubert, R. Wojdanowski, A. Zimek, H.-P. Kriegel
* On Evaluation of Outlier Rankings and Outlier Scores
* In Proceedings of the 12th SIAM International Conference on Data Mining
* (SDM), Anaheim, CA, 2012.
*
*
* @author Erich Schubert
* @since 0.5.0
*
* @apiviz.composedOf VisualizerParameterizer
* @apiviz.composedOf SimilarityMatrixVisualizer
*/
@Reference(authors = "E. Schubert, R. Wojdanowski, A. Zimek, H.-P. Kriegel", //
title = "On Evaluation of Outlier Rankings and Outlier Scores", //
booktitle = "Proc. 12th SIAM International Conference on Data Mining (SDM), Anaheim, CA, 2012.", //
url = "http://dx.doi.org/10.1137/1.9781611972825.90")
public class VisualizePairwiseGainMatrix extends AbstractApplication {
/**
* Get static logger.
*/
private static final Logging LOG = Logging.getLogger(VisualizePairwiseGainMatrix.class);
/**
* The data input part.
*/
private InputStep inputstep;
/**
* Parameterizer for visualizers.
*/
private VisualizerParameterizer vispar;
/**
* Outlier scaling to apply during preprocessing.
*/
private ScalingFunction prescaling;
/**
* Ensemble voting function.
*/
private EnsembleVoting voting;
/**
* Constructor.
*
* @param inputstep Input step
* @param prescaling Scaling function for input scores.
* @param voting Voting function
* @param vispar Visualizer parameterizer
*/
public VisualizePairwiseGainMatrix(InputStep inputstep, ScalingFunction prescaling, EnsembleVoting voting, VisualizerParameterizer vispar) {
super();
this.inputstep = inputstep;
this.prescaling = prescaling;
this.voting = voting;
this.vispar = vispar;
}
@Override
public void run() {
final Database database = inputstep.getDatabase();
ResultHierarchy hier = database.getHierarchy();
Relation relation = database.getRelation(TypeUtil.NUMBER_VECTOR_FIELD);
final Relation labels = DatabaseUtil.guessLabelRepresentation(database);
final DBID firstid = DBIDUtil.deref(labels.iterDBIDs());
final String firstlabel = labels.get(firstid);
if(!firstlabel.matches(".*by.?label.*")) {
throw new AbortException("No 'by label' reference outlier found, which is needed for weighting!");
}
relation = GreedyEnsembleExperiment.applyPrescaling(prescaling, relation, firstid);
// Dimensionality and reference vector
final int dim = RelationUtil.dimensionality(relation);
final NumberVector refvec = relation.get(firstid);
// Build the truth vector
VectorNonZero pos = new VectorNonZero(refvec);
ArrayModifiableDBIDs ids = DBIDUtil.newArray(relation.getDBIDs());
ids.remove(firstid);
ids.sort();
final int size = ids.size();
double[][] data = new double[size][size];
DoubleMinMax minmax = new DoubleMinMax(), commax = new DoubleMinMax();
{
FiniteProgress prog = LOG.isVerbose() ? new FiniteProgress("Computing ensemble gain.", size * (size + 1) >> 1, LOG) : null;
double[] buf = new double[2]; // Vote combination buffer.
int a = 0;
for(DBIDIter id = ids.iter(); id.valid(); id.advance(), a++) {
final NumberVector veca = relation.get(id);
// Direct AUC score:
{
double auc = ROCEvaluation.computeROCAUC(pos, new DecreasingVectorIter(veca));
data[a][a] = auc;
// minmax.put(auc);
LOG.incrementProcessed(prog);
}
// Compare to others, exploiting symmetry
DBIDArrayIter id2 = ids.iter();
id2.seek(a + 1);
for(int b = a + 1; b < size; b++, id2.advance()) {
final NumberVector vecb = relation.get(id2);
double[] combined = new double[dim];
for(int d = 0; d < dim; d++) {
buf[0] = veca.doubleValue(d);
buf[1] = vecb.doubleValue(d);
combined[d] = voting.combine(buf);
}
double auc = ROCEvaluation.computeROCAUC(pos, new DecreasingVectorIter(new Vector(combined)));
// logger.verbose(auc + " " + labels.get(ids.get(a)) + " " +
// labels.get(ids.get(b)));
data[a][b] = auc;
data[b][a] = auc;
commax.put(data[a][b]);
// minmax.put(auc);
LOG.incrementProcessed(prog);
}
}
LOG.ensureCompleted(prog);
}
for(int a = 0; a < size; a++) {
for(int b = a + 1; b < size; b++) {
double ref = Math.max(data[a][a], data[b][b]);
data[a][b] = (data[a][b] - ref) / (1 - ref);
data[b][a] = (data[b][a] - ref) / (1 - ref);
// logger.verbose(data[a][b] + " " + labels.get(ids.get(a)) + " " +
// labels.get(ids.get(b)));
minmax.put(data[a][b]);
}
}
for(int a = 0; a < size; a++) {
data[a][a] = 0;
}
LOG.verbose("Gain: " + minmax.toString() + " AUC: " + commax.toString());
boolean hasneg = (minmax.getMin() < -1E-3);
LinearScaling scale;
if(!hasneg) {
scale = LinearScaling.fromMinMax(0., minmax.getMax());
}
else {
scale = LinearScaling.fromMinMax(0.0, Math.max(minmax.getMax(), -minmax.getMin()));
}
scale = LinearScaling.fromMinMax(0., .5);
BufferedImage img = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
for(int x = 0; x < size; x++) {
for(int y = x; y < size; y++) {
double val = data[x][y];
val = Math.max(-1, Math.min(1., scale.getScaled(val)));
// Compute color:
final int col;
{
if(val >= 0) {
int ival = 0xFF & (int) (255 * val);
col = 0xff000000 | (ival << 8);
}
else {
int ival = 0xFF & (int) (255 * -val);
col = 0xff000000 | (ival << 16);
}
}
img.setRGB(x, y, col);
img.setRGB(y, x, col);
}
}
SimilarityMatrix smat = new ComputeSimilarityMatrixImage.SimilarityMatrix(img, relation, ids);
hier.add(database, smat);
VisualizerContext context = vispar.newContext(hier, smat);
// Attach visualizers to results
SimilarityMatrixVisualizer factory = new SimilarityMatrixVisualizer();
factory.processNewResult(context, database);
Hierarchy.Iter it = VisualizationTree.filter(context, VisualizationTask.class);
for(; it.valid(); it.advance()) {
VisualizationTask task = it.get();
if(task.getFactory() == factory) {
showVisualization(context, factory, task);
}
}
}
/**
* Show a single visualization.
*
* @param context Visualization context
* @param factory Visualizer factory
* @param task Visualization task
*/
private void showVisualization(VisualizerContext context, SimilarityMatrixVisualizer factory, VisualizationTask task) {
VisualizationPlot plot = new VisualizationPlot();
Visualization vis = factory.makeVisualization(task, plot, 1.0, 1.0, null);
plot.getRoot().appendChild(vis.getLayer());
plot.getRoot().setAttribute(SVGConstants.SVG_WIDTH_ATTRIBUTE, "20cm");
plot.getRoot().setAttribute(SVGConstants.SVG_HEIGHT_ATTRIBUTE, "20cm");
plot.getRoot().setAttribute(SVGConstants.SVG_VIEW_BOX_ATTRIBUTE, "0 0 1 1");
plot.updateStyleElement();
(new SimpleSVGViewer()).setPlot(plot);
}
/**
* Parameterization class.
*
* @author Erich Schubert
*
* @apiviz.exclude
*/
public static class Parameterizer extends AbstractApplication.Parameterizer {
/**
* Data source.
*/
private InputStep inputstep;
/**
* Parameterizer for visualizers.
*/
private VisualizerParameterizer vispar;
/**
* Outlier scaling to apply during preprocessing.
*/
private ScalingFunction prescaling;
/**
* Voring function.
*/
private EnsembleVoting voting;
@Override
protected void makeOptions(Parameterization config) {
super.makeOptions(config);
// Data input
inputstep = config.tryInstantiate(InputStep.class);
// Visualization options
vispar = config.tryInstantiate(VisualizerParameterizer.class);
// Prescaling
ObjectParameter prescalingP = new ObjectParameter<>(GreedyEnsembleExperiment.Parameterizer.PRESCALING_ID, ScalingFunction.class);
prescalingP.setOptional(true);
if(config.grab(prescalingP)) {
prescaling = prescalingP.instantiateClass(config);
}
ObjectParameter votingP = new ObjectParameter<>(GreedyEnsembleExperiment.Parameterizer.VOTING_ID, EnsembleVoting.class, EnsembleVotingMean.class);
if(config.grab(votingP)) {
voting = votingP.instantiateClass(config);
}
}
@Override
protected VisualizePairwiseGainMatrix makeInstance() {
return new VisualizePairwiseGainMatrix(inputstep, prescaling, voting, vispar);
}
}
/**
* Main method.
*
* @param args Command line parameters.
*/
public static void main(String[] args) {
runCLIApplication(VisualizePairwiseGainMatrix.class, args);
}
}
elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/result/ 0000775 0000000 0000000 00000000000 12657057427 0026511 5 ustar 00root root 0000000 0000000 AutomaticVisualization.java 0000664 0000000 0000000 00000012633 12657057427 0034012 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/result package de.lmu.ifi.dbs.elki.result;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2016
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import javax.swing.JFrame;
import de.lmu.ifi.dbs.elki.gui.GUIUtil;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.result.Result;
import de.lmu.ifi.dbs.elki.result.ResultHandler;
import de.lmu.ifi.dbs.elki.result.ResultHierarchy;
import de.lmu.ifi.dbs.elki.result.ResultUtil;
import de.lmu.ifi.dbs.elki.utilities.Alias;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.Flag;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.StringParameter;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.VisualizerParameterizer;
import de.lmu.ifi.dbs.elki.visualization.gui.ResultWindow;
/**
* Handler to process and visualize a Result.
*
* @author Erich Schubert
* @author Remigius Wojdanowski
* @since 0.3
*
* @apiviz.composedOf VisualizerParameterizer
* @apiviz.uses ResultWindow oneway
*/
@Alias({ "visualizer", "vis", "ResultVisualizer", "de.lmu.ifi.dbs.elki.visualization.gui.ResultVisualizer" })
public class AutomaticVisualization implements ResultHandler {
/**
* Get a logger for this class.
*/
private static final Logging LOG = Logging.getLogger(AutomaticVisualization.class);
/**
* Stores the set title.
*/
String title;
/**
* Default title
*/
protected static final String DEFAULT_TITLE = "ELKI Result Visualization";
/**
* Visualization manager.
*/
VisualizerParameterizer manager;
/**
* Single view mode
*/
boolean single;
/**
* Current result window.
*/
ResultWindow window;
/**
* Constructor.
*
* @param title Window title
* @param manager Parameterization manager for visualizers
* @param single Flag to indicat single-view mode.
*/
public AutomaticVisualization(String title, VisualizerParameterizer manager, boolean single) {
super();
this.title = title;
this.manager = manager;
this.single = single;
}
@Override
public void processNewResult(final ResultHierarchy hier, final Result result) {
if(window == null) {
if(title == null) {
title = VisualizerParameterizer.getTitle(ResultUtil.findDatabase(hier), result);
if(title == null) {
title = DEFAULT_TITLE;
}
}
GUIUtil.setLookAndFeel();
VisualizerContext context = manager.newContext(hier, result);
window = new ResultWindow(title, context, single);
}
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
window.setVisible(true);
window.setExtendedState(window.getExtendedState() | JFrame.MAXIMIZED_BOTH);
}
catch(Throwable e) {
LOG.exception("Error in starting visualizer window.", e);
}
}
});
}
/**
* Parameterization class.
*
* @author Erich Schubert
*
* @apiviz.exclude
*/
public static class Parameterizer extends AbstractParameterizer {
/**
* Parameter to specify the window title
*
* Key: {@code -vis.window.title}
*
*
* Default value: "ELKI Result Visualization"
*
*/
public static final OptionID WINDOW_TITLE_ID = new OptionID("vis.window.title", "Title to use for visualization window.");
/**
* Flag to set single display
*
*
* Key: -vis.single
*
*/
public static final OptionID SINGLE_ID = new OptionID("vis.window.single", "Embed visualizers in a single window, not using thumbnails and detail views.");
/**
* Stores the set title.
*/
String title;
/**
* Visualization manager.
*/
VisualizerParameterizer manager;
/**
* Single view mode.
*/
boolean single = false;
@Override
protected void makeOptions(Parameterization config) {
super.makeOptions(config);
StringParameter titleP = new StringParameter(WINDOW_TITLE_ID);
titleP.setOptional(true);
if(config.grab(titleP)) {
title = titleP.getValue();
}
Flag singleF = new Flag(SINGLE_ID);
if(config.grab(singleF)) {
single = singleF.isTrue();
}
manager = config.tryInstantiate(VisualizerParameterizer.class);
}
@Override
protected AutomaticVisualization makeInstance() {
return new AutomaticVisualization(title, manager, single);
}
}
}
elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/result/ExportVisualizations.java0000664 0000000 0000000 00000022517 12657057427 0033611 0 ustar 00root root 0000000 0000000 package de.lmu.ifi.dbs.elki.result;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.batik.util.SVGConstants;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.result.Result;
import de.lmu.ifi.dbs.elki.result.ResultHandler;
import de.lmu.ifi.dbs.elki.result.ResultHierarchy;
import de.lmu.ifi.dbs.elki.utilities.Alias;
import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.Hierarchy;
import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.CommonConstraints;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.FileParameter;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.FileParameter.FileType;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.VisualizerParameterizer;
import de.lmu.ifi.dbs.elki.visualization.gui.VisualizationPlot;
import de.lmu.ifi.dbs.elki.visualization.gui.overview.PlotItem;
import de.lmu.ifi.dbs.elki.visualization.projector.Projector;
import de.lmu.ifi.dbs.elki.visualization.visualizers.Visualization;
/**
* Class that automatically generates all visualizations and exports them into
* SVG files. To configure the export, you will want to configure the
* {@link VisualizerParameterizer}, in particular the pattern for choosing which
* visualizers to run.
*
* @author Erich Schubert
* @since 0.5.0
*
* @apiviz.composedOf VisualizerParameterizer
*/
@Alias("de.lmu.ifi.dbs.elki.visualization.ExportVisualizations")
public class ExportVisualizations implements ResultHandler {
/**
* Get a logger for this class.
*/
private static final Logging LOG = Logging.getLogger(ExportVisualizations.class);
/**
* Output folder
*/
File output;
/**
* Visualization manager.
*/
VisualizerParameterizer manager;
/**
* Ratio for canvas
*/
double ratio;
/**
* Base result
*/
Result baseResult = null;
/**
* Visualizer context
*/
VisualizerContext context = null;
/**
* Output counter.
*/
Map counter = new HashMap<>();
/**
* Constructor.
*
* @param output Output folder
* @param manager Parameterizer
* @param ratio Canvas ratio
*/
public ExportVisualizations(File output, VisualizerParameterizer manager, double ratio) {
super();
this.output = output;
this.manager = manager;
this.ratio = ratio;
}
@Override
public void processNewResult(ResultHierarchy hier, Result newResult) {
if(output.isFile()) {
throw new AbortException("Output folder cannot be an existing file.");
}
if(!output.exists()) {
if(!output.mkdirs()) {
throw new AbortException("Could not create output directory.");
}
}
if(this.baseResult == null) {
this.baseResult = newResult;
context = null;
counter = new HashMap<>();
LOG.warning("Note: Reusing visualization exporter for more than one result is untested.");
}
if(context == null) {
context = manager.newContext(hier, baseResult);
}
// Projected visualizations
Hierarchy
*/
public static final OptionID STYLELIB_ID = new OptionID("visualizer.stylesheet", "Style properties file to use, included properties: classic, default, greyscale, neon, presentation, print");
/**
* Parameter to enable visualizers
*
*
* Key: -vis.enable
*
* Default: ELKI core
*
*/
public static final OptionID ENABLEVIS_ID = new OptionID("vis.enable", "Visualizers to enable by default.");
/**
* Parameter to set the sampling level
*
*
* Key: -vis.sampling
*
*/
public static final OptionID SAMPLING_ID = new OptionID("vis.sampling", "Maximum number of objects to visualize by default (for performance reasons).");
/**
* Style library
*/
protected StyleLibrary stylelib = null;
/**
* Pattern to enable visualizers
*/
protected Pattern enableVisualizers = null;
/**
* Visualizer factories
*/
protected Collection factories = null;
/**
* Sampling size
*/
protected int samplesize = -1;
@Override
protected void makeOptions(Parameterization config) {
super.makeOptions(config);
IntParameter samplingP = new IntParameter(SAMPLING_ID, DEFAULT_SAMPLE_SIZE) //
.addConstraint(CommonConstraints.GREATER_EQUAL_MINUSONE_INT);
if(config.grab(samplingP)) {
samplesize = samplingP.intValue();
}
StringParameter stylelibP = new StringParameter(STYLELIB_ID, PropertiesBasedStyleLibrary.DEFAULT_SCHEME_FILENAME);
if(config.grab(stylelibP)) {
String filename = stylelibP.getValue();
try {
stylelib = new PropertiesBasedStyleLibrary(filename, filename);
}
catch(AbortException e) {
config.reportError(new WrongParameterValueException(stylelibP, filename, e));
}
}
PatternParameter enablevisP = new PatternParameter(ENABLEVIS_ID) //
.setOptional(true);
if(config.grab(enablevisP)) {
if(!"all".equals(enablevisP.getValueAsString())) {
enableVisualizers = enablevisP.getValue();
}
}
MergedParameterization merged = new MergedParameterization(config);
factories = collectFactorys(merged, enableVisualizers);
}
/**
* Collect and instantiate all visualizer factories.
*
* @param config Parameterization
* @param filter Filter
* @return List of all adapters found.
*/
private static Collection collectFactorys(MergedParameterization config, Pattern filter) {
ArrayList factories = new ArrayList<>();
for(Class> c : ELKIServiceRegistry.findAllImplementations(VisualizationProcessor.class)) {
if(filter != null && !filter.matcher(c.getCanonicalName()).find()) {
continue;
}
try {
config.rewind();
VisualizationProcessor a = ClassGenericsUtil.tryInstantiate(VisualizationProcessor.class, c, config);
factories.add(a);
}
catch(Throwable e) {
if(LOG.isDebugging()) {
LOG.exception("Error instantiating visualization processor " + c.getName(), e.getCause());
}
else {
LOG.warning("Error instantiating visualization processor " + c.getName() + ": " + e.getMessage());
}
}
}
return factories;
}
@Override
protected VisualizerParameterizer makeInstance() {
return new VisualizerParameterizer(samplesize, stylelib, factories);
}
}
}
elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/batikutil/ 0000775 0000000 0000000 00000000000 12657057427 0032064 5 ustar 00root root 0000000 0000000 AddCSSClass.java 0000775 0000000 0000000 00000003135 12657057427 0034704 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/batikutil package de.lmu.ifi.dbs.elki.visualization.batikutil;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.w3c.dom.Element;
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventListener;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
/**
* Add a CSS class to the event target.
*
* @author Erich Schubert
* @since 0.2
*
*/
public class AddCSSClass implements EventListener {
/**
* Class to set
*/
private String cssclass;
/**
* Constructor
* @param cssclass class to set
*/
public AddCSSClass(String cssclass) {
super();
this.cssclass = cssclass;
}
/**
* Event handler
*/
@Override
public void handleEvent(Event evt) {
Element e = (Element) evt.getTarget();
SVGUtil.addCSSClass(e, cssclass);
}
} AttributeModifier.java 0000664 0000000 0000000 00000003637 12657057427 0036303 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/batikutil package de.lmu.ifi.dbs.elki.visualization.batikutil;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.w3c.dom.Element;
/**
* Runnable wrapper for modifying XML-Attributes.
*
* @author Remigius Wojdanowski
* @since 0.3
*
*/
// FIXME: Unused? Remove?
public class AttributeModifier implements Runnable {
/**
* Provides the attribute to be modified.
*/
private Element e;
/**
* The name of the attribute to be modified.
*/
private String attribute;
/**
* The new value of the attribute.
*/
private String newValue;
/**
* Trivial constructor.
*
* @param e provides the attribute to be modified.
* @param attribute the name of the attribute to be modified.
* @param newValue the new value of the attribute.
*/
public AttributeModifier(Element e, String attribute, String newValue) {
this.e = e;
this.attribute = attribute;
this.newValue = newValue;
}
@Override
public void run() {
if(newValue != null) {
e.setAttribute(attribute, newValue);
}
else {
e.removeAttribute(attribute);
}
}
}
BatikUtil.java 0000664 0000000 0000000 00000005564 12657057427 0034552 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/batikutil package de.lmu.ifi.dbs.elki.visualization.batikutil;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2016
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.apache.batik.dom.events.DOMMouseEvent;
import org.w3c.dom.Element;
import org.w3c.dom.events.Event;
import org.w3c.dom.svg.SVGElement;
import org.w3c.dom.svg.SVGLocatable;
import org.w3c.dom.svg.SVGMatrix;
import org.w3c.dom.svg.SVGPoint;
/**
* Batik helper class with static methods.
*
* @author Erich Schubert
* @since 0.3
*/
public final class BatikUtil {
/**
* Get the relative coordinates of a point within the coordinate system of a
* particular SVG Element.
*
* @param evt Event, needs to be a DOMMouseEvent
* @param reference SVG Element the coordinate system is used of
* @return Array containing the X and Y values
*/
public static double[] getRelativeCoordinates(Event evt, Element reference) {
if(evt instanceof DOMMouseEvent && reference instanceof SVGLocatable && reference instanceof SVGElement) {
// Get the screen (pixel!) coordinates
DOMMouseEvent gnme = (DOMMouseEvent) evt;
SVGMatrix mat = ((SVGLocatable) reference).getScreenCTM();
SVGMatrix imat = mat.inverse();
SVGPoint cPt = ((SVGElement) reference).getOwnerSVGElement().createSVGPoint();
cPt.setX(gnme.getClientX());
cPt.setY(gnme.getClientY());
// Have Batik transform the screen (pixel!) coordinates into SVG element
// coordinates
cPt = cPt.matrixTransform(imat);
return new double[] { cPt.getX(), cPt.getY() };
}
return null;
}
/**
* Test whether FOP were installed (for PDF, PS and EPS output support).
*
* @return {@code true} when FOP is available.
*/
public static boolean hasFOPInstalled() {
try {
Class> c1 = Class.forName("org.apache.fop.svg.PDFTranscoder");
Class> c2 = Class.forName("org.apache.fop.render.ps.PSTranscoder");
Class> c3 = Class.forName("org.apache.fop.render.ps.EPSTranscoder");
return (c1 != null) && (c2 != null) && (c3 != null);
}
catch(ClassNotFoundException e) {
return false;
}
}
}
CSSHoverClass.java 0000775 0000000 0000000 00000005654 12657057427 0035307 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/batikutil package de.lmu.ifi.dbs.elki.visualization.batikutil;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventListener;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
/**
* Do a hover effect using a CSS class.
*
* @author Erich Schubert
* @since 0.2
*
*/
public class CSSHoverClass implements EventListener {
/**
* Class to set when over
*/
private String overclass;
/**
* Class to set when out
*/
private String outclass;
/**
* Consider a click as 'out'?
*/
private boolean clickisout;
/**
* Constructor
*
* @param overclass class to set when over
* @param outclass class to set when out
* @param clickisout consider a click to be an 'out' event
*/
public CSSHoverClass(String overclass, String outclass, boolean clickisout) {
super();
this.overclass = overclass;
this.outclass = outclass;
this.clickisout = clickisout;
}
/**
* Constructor without 'clickisout' option.
*
* @param overclass class to set when over
* @param outclass class to set when out
*/
public CSSHoverClass(String overclass, String outclass) {
this(overclass, outclass, false);
}
/**
* Event handler
*/
@Override
public void handleEvent(Event evt) {
Element e = (Element) evt.getTarget();
if (SVGConstants.SVG_EVENT_MOUSEOVER.equals(evt.getType())) {
if (overclass != null) {
SVGUtil.addCSSClass(e, overclass);
}
if (outclass != null) {
SVGUtil.removeCSSClass(e, outclass);
}
}
if (SVGConstants.SVG_EVENT_MOUSEOUT.equals(evt.getType())) {
if (overclass != null) {
SVGUtil.removeCSSClass(e, overclass);
}
if (outclass != null) {
SVGUtil.addCSSClass(e, outclass);
}
}
if (clickisout && SVGConstants.SVG_EVENT_CLICK.equals(evt.getType())) {
if (overclass != null) {
SVGUtil.removeCSSClass(e, overclass);
}
if (outclass != null) {
SVGUtil.addCSSClass(e, outclass);
}
}
}
}
CloneInlineImages.java 0000664 0000000 0000000 00000011436 12657057427 0036202 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/batikutil package de.lmu.ifi.dbs.elki.visualization.batikutil;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.awt.image.renderable.RenderableImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
import org.apache.batik.svggen.SVGSyntax;
import org.apache.batik.util.Base64EncoderStream;
import org.apache.batik.util.ParsedURL;
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import de.lmu.ifi.dbs.elki.logging.LoggingUtil;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGCloneVisible;
/**
* Clone an SVG document, inlining temporary and in-memory linked images.
*
* @author Erich Schubert
* @since 0.5.0
*
* @apiviz.has ThumbnailRegistryEntry
*/
public class CloneInlineImages extends SVGCloneVisible {
@Override
public Node cloneNode(Document doc, Node eold) {
Node enew = null;
if(eold instanceof Element) {
Element e = (Element) eold;
if(e.getTagName().equals(SVGConstants.SVG_IMAGE_TAG)) {
String url = e.getAttributeNS(SVGConstants.XLINK_NAMESPACE_URI, SVGConstants.XLINK_HREF_ATTRIBUTE);
ParsedURL urldata = new ParsedURL(url);
if(ThumbnailRegistryEntry.isCompatibleURLStatic(urldata)) {
enew = inlineThumbnail(doc, urldata, eold);
}
else if("file".equals(urldata.getProtocol())) {
enew = inlineExternal(doc, urldata, eold);
}
}
}
if(enew != null) {
return enew;
}
return super.cloneNode(doc, eold);
}
/**
* Inline a referenced thumbnail.
*
* @param doc Document (element factory)
* @param urldata URL
* @param eold Existing node
* @return Replacement node, or {@code null}
*/
protected Node inlineThumbnail(Document doc, ParsedURL urldata, Node eold) {
RenderableImage img = ThumbnailRegistryEntry.handleURL(urldata);
if(img == null) {
LoggingUtil.warning("Image not found in registry: " + urldata.toString());
return null;
}
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
os.write(SVGSyntax.DATA_PROTOCOL_PNG_PREFIX.getBytes());
Base64EncoderStream encoder = new Base64EncoderStream(os);
ImageIO.write(img.createDefaultRendering(), "png", encoder);
encoder.close();
}
catch(IOException e) {
LoggingUtil.exception("Exception serializing image to png", e);
return null;
}
Element i = (Element) super.cloneNode(doc, eold);
i.setAttributeNS(SVGConstants.XLINK_NAMESPACE_URI, SVGConstants.XLINK_HREF_ATTRIBUTE, os.toString().replaceAll("\\s*[\\r\\n]+\\s*", ""));
return i;
}
/**
* Inline an external file (usually from temp).
*
* @param doc Document (element factory)
* @param urldata URL
* @param eold Existing node
* @return Replacement node, or {@code null}
*/
protected Node inlineExternal(Document doc, ParsedURL urldata, Node eold) {
File in = new File(urldata.getPath());
if(!in.exists()) {
LoggingUtil.warning("Referencing non-existant file: " + urldata.toString());
return null;
}
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
os.write(SVGSyntax.DATA_PROTOCOL_PNG_PREFIX.getBytes());
Base64EncoderStream encoder = new Base64EncoderStream(os);
FileInputStream instream = new FileInputStream(in);
byte[] buf = new byte[4096];
while(true) {
int read = instream.read(buf, 0, buf.length);
if(read <= 0) {
break;
}
encoder.write(buf, 0, read);
}
instream.close();
encoder.close();
}
catch(IOException e) {
LoggingUtil.exception("Exception serializing image to png", e);
return null;
}
Element i = (Element) super.cloneNode(doc, eold);
i.setAttributeNS(SVGConstants.XLINK_NAMESPACE_URI, SVGConstants.XLINK_HREF_ATTRIBUTE, os.toString().replaceAll("\\s*[\\r\\n]+\\s*", ""));
return i;
}
} DragableArea.java 0000664 0000000 0000000 00000025772 12657057427 0035157 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/batikutil package de.lmu.ifi.dbs.elki.visualization.batikutil;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventListener;
import org.w3c.dom.events.EventTarget;
import org.w3c.dom.svg.SVGPoint;
import de.lmu.ifi.dbs.elki.logging.LoggingUtil;
import de.lmu.ifi.dbs.elki.visualization.css.CSSClass;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGPlot;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
/**
* A simple dragable area for Batik.
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.has DragListener
* @apiviz.has Element
*/
public class DragableArea implements EventListener {
/**
* Our element node.
*/
final protected Element element;
/**
* The coordinate system node.
*/
final protected Element coordref;
/**
* The plot we are attached to.
*/
final protected SVGPlot svgp;
/**
* The point where the drag started.
*/
protected SVGPoint startDragPoint = null;
/**
* A listener to notify on drags (when not subclassing).
*/
protected DragListener listener = null;
/**
* Constructor for a dragable area. use getElement() to get the DOM node.
*
* Note: always remember to call 'destroy()' to remove listeners!
*
* @param plot Plot we'll be added to
* @param x X position
* @param y Y position
* @param w Width
* @param h Height
*/
public DragableArea(SVGPlot plot, double x, double y, double w, double h) {
this.svgp = plot;
this.element = plot.svgRect(x, y, w, h);
makeInvisible();
this.coordref = this.element;
enableStart();
}
/**
* Constructor for a dragable area. use getElement() to get the DOM node.
*
* Note: always remember to call 'destroy()' to remove listeners!
*
* @param plot Plot we'll be added to
* @param coordref Element defining the coordinate system
* @param x X position
* @param y Y position
* @param w Width
* @param h Height
*/
public DragableArea(SVGPlot plot, Element coordref, double x, double y, double w, double h) {
this.svgp = plot;
this.element = plot.svgRect(x, y, w, h);
makeInvisible();
this.coordref = coordref;
enableStart();
}
/**
* Constructor for a dragable area. use getElement() to get the DOM node.
*
* Note: always remember to call 'destroy()' to remove listeners!
*
* @param plot Plot we'll be added to
* @param x X position
* @param y Y position
* @param w Width
* @param h Height
* @param listener Drag listener
*/
public DragableArea(SVGPlot plot, double x, double y, double w, double h, DragListener listener) {
this.svgp = plot;
this.element = plot.svgRect(x, y, w, h);
makeInvisible();
this.coordref = this.element;
this.listener = listener;
enableStart();
}
/**
* Constructor for a dragable area. use getElement() to get the DOM node.
*
* Note: always remember to call 'destroy()' to remove listeners!
*
* @param plot Plot we'll be added to
* @param coordref Element defining the coordinate system
* @param x X position
* @param y Y position
* @param w Width
* @param h Height
* @param listener Drag listener
*/
public DragableArea(SVGPlot plot, Element coordref, double x, double y, double w, double h, DragListener listener) {
this.svgp = plot;
this.element = plot.svgRect(x, y, w, h);
makeInvisible();
this.coordref = coordref;
this.listener = listener;
enableStart();
}
/**
* Remove the listeners
*/
public void destroy() {
disableStart();
disableStop();
}
/**
* The DOM element.
*
* @return the element
*/
public Element getElement() {
return element;
}
/**
* Enable capturing of 'mousedown' events.
*/
public void enableStart() {
EventTarget targ = (EventTarget) element;
targ.addEventListener(SVGConstants.SVG_EVENT_MOUSEDOWN, this, false);
}
/**
* Disable capturing of 'mousedown' events.
*/
public void disableStart() {
EventTarget targ = (EventTarget) element;
targ.removeEventListener(SVGConstants.SVG_EVENT_MOUSEDOWN, this, false);
}
/**
* Enable capturing of 'mousemove' and 'mouseup' events.
*/
protected void enableStop() {
EventTarget targ = svgp.getDocument().getRootElement();
targ.addEventListener(SVGConstants.SVG_EVENT_MOUSEMOVE, this, false);
targ.addEventListener(SVGConstants.SVG_EVENT_MOUSEUP, this, false);
// FIXME: listen on the background object!
targ.addEventListener(SVGConstants.SVG_EVENT_MOUSEOUT, this, false);
}
/**
* Disable capturing of 'mousemove' and 'mouseup' events.
*/
protected void disableStop() {
EventTarget targ = svgp.getDocument().getRootElement();
targ.removeEventListener(SVGConstants.SVG_EVENT_MOUSEMOVE, this, false);
targ.removeEventListener(SVGConstants.SVG_EVENT_MOUSEUP, this, false);
// FIXME: listen on the background object!
targ.removeEventListener(SVGConstants.SVG_EVENT_MOUSEOUT, this, false);
}
@Override
public void handleEvent(Event evt) {
if (evt.getType().equals(SVGConstants.SVG_EVENT_MOUSEDOWN)) {
SVGPoint dragPoint = getCoordinates(evt);
if (startDrag(dragPoint, evt)) {
// LoggingUtil.warning("Starting drag: "+dragPoint);
startDragPoint = dragPoint;
enableStop();
}
} else if (evt.getType().equals(SVGConstants.SVG_EVENT_MOUSEMOVE)) {
if (startDragPoint != null) {
SVGPoint dragPoint = getCoordinates(evt);
if (!duringDrag(startDragPoint, dragPoint, evt, evt.getTarget() == element)) {
// cancel the drag operation
startDragPoint = null;
disableStop();
}
}
} else if (evt.getType().equals(SVGConstants.SVG_EVENT_MOUSEUP)) {
if (startDragPoint != null) {
SVGPoint dragPoint = getCoordinates(evt);
if (endDrag(startDragPoint, dragPoint, evt, evt.getTarget() == element)) {
// LoggingUtil.warning("Drag completed: "+dragPoint);
startDragPoint = null;
disableStop();
}
}
} else if (evt.getType().equals(SVGConstants.SVG_EVENT_MOUSEOUT)) {
// When leaving the document with the mouse!
if (startDragPoint != null && evt.getTarget() == evt.getCurrentTarget()) {
// LoggingUtil.warning("Mouseout: "+evt.getTarget().toString());
SVGPoint dragPoint = getCoordinates(evt);
if (endDrag(startDragPoint, dragPoint, evt, false)) {
// LoggingUtil.warning("Drag completed: "+dragPoint);
startDragPoint = null;
disableStop();
}
}
} else {
LoggingUtil.warning("Unrecognized event: " + evt);
}
}
/**
* Return the event coordinates for this event.
*
* @param evt Event
* @return Coordinates
*/
protected SVGPoint getCoordinates(Event evt) {
return SVGUtil.elementCoordinatesFromEvent(this.svgp.getDocument(), this.coordref, evt);
}
/**
* Action to do on drag start.
*
* @param startPoint Point where the drag was started.
* @param evt The event object
* @return {@code true} to start the drag operation
*/
protected boolean startDrag(SVGPoint startPoint, Event evt) {
if (listener != null) {
return listener.startDrag(startPoint, evt);
}
return true;
}
/**
* Method called during drags.
*
* @param startPoint Drag starting point
* @param dragPoint Drag end point
* @param evt The event object
* @param inside Inside the tracked element
* @return {@code true} to continue the drag
*/
protected boolean duringDrag(SVGPoint startPoint, SVGPoint dragPoint, Event evt, boolean inside) {
if (listener != null) {
return listener.duringDrag(startPoint, dragPoint, evt, inside);
}
return true;
}
/**
* Method called when a drag was ended.
*
* @param startPoint Drag starting point
* @param dragPoint Drag end point
* @param evt The event object
* @param inside Success flag
* @return {@code true} to complete the drag
*/
protected boolean endDrag(SVGPoint startPoint, SVGPoint dragPoint, Event evt, boolean inside) {
if (listener != null) {
return listener.endDrag(startPoint, dragPoint, evt, inside);
}
return true;
}
/**
* Make the rectangle invisible.
*/
public void makeInvisible() {
CSSClass cls = new CSSClass(this, "unused");
cls.setStatement(SVGConstants.CSS_FILL_OPACITY_PROPERTY, "0");
cls.setStatement(SVGConstants.CSS_CURSOR_PROPERTY, SVGConstants.CSS_POINTER_VALUE);
SVGUtil.setAtt(element, SVGConstants.SVG_STYLE_ATTRIBUTE, cls.inlineCSS());
}
/**
* Make the rectangle visible, for debug purposes.
*/
public void makeVisible() {
CSSClass cls = new CSSClass(this, "unused");
cls.setStatement(SVGConstants.CSS_FILL_PROPERTY, SVGConstants.CSS_GREEN_VALUE);
cls.setStatement(SVGConstants.CSS_FILL_OPACITY_PROPERTY, "0.2");
cls.setStatement(SVGConstants.CSS_CURSOR_PROPERTY, SVGConstants.CSS_POINTER_VALUE);
SVGUtil.setAtt(element, SVGConstants.SVG_STYLE_ATTRIBUTE, cls.inlineCSS());
}
/**
* Listener interface for drag events.
*
* @author Erich Schubert
*
* @apiviz.excludeSubtypes
*/
public interface DragListener {
/**
* Action to do on drag start.
*
* @param startPoint Point where the drag was started.
* @param evt The event object
* @return {@code true} to start the drag operation
*/
boolean startDrag(SVGPoint startPoint, Event evt);
/**
* Method called during drags.
*
* @param startPoint Drag starting point
* @param dragPoint Drag end point
* @param evt The event object
* @param inside Inside the tracked element
* @return {@code true} to continue the drag
*/
boolean duringDrag(SVGPoint startPoint, SVGPoint dragPoint, Event evt, boolean inside);
/**
* Method called when a drag was ended.
*
* @param startPoint Drag starting point
* @param dragPoint Drag end point
* @param evt The event object
* @param inside Whether the end point was inside the area
* @return {@code true} to complete the drag
*/
boolean endDrag(SVGPoint startPoint, SVGPoint dragPoint, Event evt, boolean inside);
}
}
JSVGSynchronizedCanvas.java 0000664 0000000 0000000 00000010764 12657057427 0037165 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/batikutil package de.lmu.ifi.dbs.elki.visualization.batikutil;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.concurrent.atomic.AtomicReference;
import org.apache.batik.bridge.UpdateManager;
import org.apache.batik.swing.JSVGCanvas;
import org.w3c.dom.Document;
import de.lmu.ifi.dbs.elki.logging.LoggingUtil;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGPlot;
/**
* An JSVGCanvas that allows easier synchronization of Updates for SVGPlot
* objects.
*
* @author Erich Schubert
* @since 0.3
*
* @apiviz.composedOf JSVGUpdateSynchronizer
* @apiviz.has SVGPlot oneway - - displays
*/
public class JSVGSynchronizedCanvas extends JSVGCanvas {
/**
* Serial version number.
*/
private static final long serialVersionUID = 1L;
/**
* Synchronizer to use when synchronizing SVG plots
*/
final private JSVGUpdateSynchronizer synchronizer;
/**
* Current SVG plot.
*/
private SVGPlot plot = null;
/**
* The latest attaching operation.
*/
private final AtomicReference latest = new AtomicReference<>();
/**
* Constructor
*/
public JSVGSynchronizedCanvas() {
super();
this.synchronizer = new JSVGUpdateSynchronizer(this);
super.setDocumentState(JSVGCanvas.ALWAYS_DYNAMIC);
}
/**
* Get the currently displayed SVG plot.
*
* @return current SVG plot. May be {@code null}!
*/
public SVGPlot getPlot() {
return this.plot;
}
/**
* Use {@link #setPlot} instead if you need synchronization!
*
* @deprecated Document cannot be synchronized - use {@link #setPlot} and a
* {@link SVGPlot} object!
*/
@Override
@Deprecated
public synchronized void setDocument(Document doc) {
// Note: this will call this.setSVGDocument!
super.setDocument(doc);
}
/**
* Choose a new plot to display.
*
* @param newplot New plot to display. May be {@code null}!
*/
public void setPlot(final SVGPlot newplot) {
synchronized(synchronizer) {
super.setSVGDocument(null);
scheduleSetPlot(this.plot, newplot);
}
}
/**
* Schedule a detach.
*
* @param oldplot Plot to detach from.
*/
private void scheduleSetPlot(final SVGPlot oldplot, final SVGPlot newplot) {
UpdateManager um = this.getUpdateManager();
if(um != null) {
synchronized(um) {
if(um.isRunning()) {
// LoggingUtil.warning("Scheduling detach: " + this + " " + oldplot);
final Runnable detach = new Runnable() {
@Override
public void run() {
if(latest.compareAndSet(this, null)) {
detachPlot(oldplot);
attachPlot(newplot);
}
}
};
latest.set(detach);
um.getUpdateRunnableQueue().preemptLater(detach);
return;
}
}
}
else {
if(oldplot != null) {
LoggingUtil.warning("No update manager, but a previous plot exists. Incorrectly initialized?");
}
}
detachPlot(oldplot);
attachPlot(newplot);
}
/**
* Attach to a new plot, and display.
*
* @param newplot Plot to attach to.
*/
private void attachPlot(SVGPlot newplot) {
this.plot = newplot;
if(newplot == null) {
super.setSVGDocument(null);
return;
}
newplot.synchronizeWith(synchronizer);
super.setSVGDocument(newplot.getDocument());
super.setDisableInteractions(newplot.getDisableInteractions());
}
/**
* Execute the detaching event.
*
* @param oldplot Plot to detach from.
*/
private void detachPlot(SVGPlot oldplot) {
if(oldplot == null) {
return;
}
this.plot = null;
oldplot.unsynchronizeWith(JSVGSynchronizedCanvas.this.synchronizer);
}
} JSVGUpdateSynchronizer.java 0000664 0000000 0000000 00000012206 12657057427 0037203 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/batikutil package de.lmu.ifi.dbs.elki.visualization.batikutil;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.lang.ref.WeakReference;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.batik.bridge.UpdateManager;
import org.apache.batik.bridge.UpdateManagerAdapter;
import org.apache.batik.bridge.UpdateManagerEvent;
import org.apache.batik.swing.svg.JSVGComponent;
import de.lmu.ifi.dbs.elki.visualization.svg.UpdateRunner;
import de.lmu.ifi.dbs.elki.visualization.svg.UpdateSynchronizer;
/**
* This class is used to synchronize SVG updates with an JSVG canvas.
*
* @author Erich Schubert
* @since 0.3
*
* @apiviz.uses UpdateRunner
*/
class JSVGUpdateSynchronizer implements UpdateSynchronizer {
/**
* A weak reference to the component the plot is in.
*/
private final WeakReference cref;
/**
* The UpdateRunner we are put into
*/
private Set> updaterunner = new CopyOnWriteArraySet<>();
/**
* Adapter to track component changes
*/
private final UMAdapter umadapter = new UMAdapter();
/**
* The current Runnable scheduled, prevents repeated invocations.
*/
private final AtomicReference pending = new AtomicReference<>();
/**
* Create an updateSynchronizer for the given component.
*
* @param component Component to manage updates on.
*/
protected JSVGUpdateSynchronizer(JSVGComponent component) {
assert(component != null);
this.cref = new WeakReference<>(component);
// Hook into UpdateManager creation.
component.addUpdateManagerListener(umadapter);
// makeRunnerIfNeeded();
}
@Override
public void activate() {
makeRunnerIfNeeded();
}
/**
* Join the runnable queue of a component.
*/
protected void makeRunnerIfNeeded() {
// We don't need to make a SVG runner when there are no pending updates.
boolean stop = true;
for(WeakReference wur : updaterunner) {
UpdateRunner ur = wur.get();
if(ur == null) {
updaterunner.remove(wur);
}
else if(!ur.isEmpty()) {
stop = false;
}
}
if(stop) {
return;
}
// We only need a new runner when we don't have one in the queue yet!
if(pending.get() != null) {
return;
}
// We need a component
JSVGComponent component = this.cref.get();
if(component == null) {
return;
}
// Synchronize with all layers:
synchronized(this) {
synchronized(component) {
UpdateManager um = component.getUpdateManager();
if(um != null) {
synchronized(um) {
if(um.isRunning()) {
// Create and insert a runner.
Runnable newrunner = new Runnable() {
@Override
public void run() {
if(pending.compareAndSet(this, null)) {
// Wake up all runners
for(WeakReference wur : updaterunner) {
UpdateRunner ur = wur.get();
if(ur == null || ur.isEmpty()) {
continue;
}
ur.runQueue();
}
}
}
};
pending.set(newrunner);
um.getUpdateRunnableQueue().invokeLater(newrunner);
return;
}
}
}
}
}
}
@Override
public void addUpdateRunner(UpdateRunner updateRunner) {
for(WeakReference wur : updaterunner) {
if(wur.get() == null) {
updaterunner.remove(wur);
}
}
updaterunner.add(new WeakReference<>(updateRunner));
}
/**
* Adapter that will track the component for UpdateManager changes.
*
* @author Erich Schubert
*
* @apiviz.exclude
*/
private class UMAdapter extends UpdateManagerAdapter {
/**
* Constructor. Protected to allow construction above.
*/
protected UMAdapter() {
// nothing to do.
}
/**
* React to an update manager becoming available.
*/
@Override
public void managerStarted(UpdateManagerEvent e) {
makeRunnerIfNeeded();
}
@Override
public void managerStopped(UpdateManagerEvent e) {
pending.set(null);
}
}
}
LazyCanvasResizer.java 0000664 0000000 0000000 00000005674 12657057427 0036303 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/batikutil package de.lmu.ifi.dbs.elki.visualization.batikutil;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.awt.Component;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
/**
* Class to lazily process canvas resize events by applying a threshold.
*
* @author Erich Schubert
* @since 0.2
*/
public abstract class LazyCanvasResizer extends ComponentAdapter {
/**
* Default threshold for resizing.
*/
public static final double DEFAULT_THRESHOLD = 0.05;
/**
* Active threshold
*/
double threshold;
/**
* Last ratio of the Canvas applied
*/
double activeRatio;
/**
* Component the ratio applies to.
*/
Component component;
/**
* Full constructor.
*
* @param component Component to track
* @param threshold Threshold
*/
public LazyCanvasResizer(Component component, double threshold) {
super();
this.threshold = threshold;
this.component = component;
this.activeRatio = getCurrentRatio();
}
/**
* Simplified constructor using the default threshold {@link #DEFAULT_THRESHOLD}
*
* @param component Component to track.
*/
public LazyCanvasResizer(Component component) {
this(component, DEFAULT_THRESHOLD);
}
/**
* React to a component resize event.
*/
@Override
public void componentResized(ComponentEvent e) {
if (e.getComponent() == component) {
double newRatio = getCurrentRatio();
if (Math.abs(newRatio - activeRatio) > threshold) {
activeRatio = newRatio;
executeResize(newRatio);
}
}
}
/**
* Get the components current ratio.
*
* @return Current ratio.
*/
public final double getCurrentRatio() {
return (double) component.getWidth() / (double) component.getHeight();
}
/**
* Callback function that needs to be overridden with actual implementations.
*
* @param newratio New ratio to apply.
*/
public abstract void executeResize(double newratio);
/**
* Get the components last applied ratio.
*
* @return Last applied ratio.
*/
public double getActiveRatio() {
return activeRatio;
}
}
NodeAppendChild.java 0000664 0000000 0000000 00000004513 12657057427 0035634 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/batikutil package de.lmu.ifi.dbs.elki.visualization.batikutil;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.w3c.dom.Element;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGPlot;
/**
* Runnable wrapper for appending XML-Elements to existing Elements.
*
* @author Remigius Wojdanowski
* @since 0.3
*/
public class NodeAppendChild implements Runnable {
/**
* Parent node to append to.
*/
protected Element parent;
/**
* The child to be appended.
*/
protected Element child;
/**
* The plot (for ID updates). May be {@code null}.
*/
protected SVGPlot plot;
/**
* The ID. May be {code null}.
*/
protected String id;
/**
* Trivial constructor.
*
* @param parent will become the parent of the appended Element.
* @param child the Element to be appended.
*/
public NodeAppendChild(Element parent, Element child) {
this(parent, child, null, null);
}
/**
* Full constructor.
*
* @param parent Parent node to append the child to
* @param child Child element
* @param plot Plot to register the ID (may be {@code null})
* @param id ID to register (may be {@code null}, requires plot to be given)
*/
public NodeAppendChild(Element parent, Element child, SVGPlot plot, String id) {
super();
this.parent = parent;
this.child = child;
this.plot = plot;
this.id = id;
}
@Override
public void run() {
parent.appendChild(child);
if(plot != null && id != null) {
plot.putIdElement(id, child);
}
}
}
NodeReplaceAllChildren.java 0000664 0000000 0000000 00000004004 12657057427 0037131 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/batikutil package de.lmu.ifi.dbs.elki.visualization.batikutil;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.w3c.dom.Element;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGPlot;
/**
* Runnable wrapper to replace all children of a given node.
*
* @author Erich Schubert
* @since 0.3
*/
public class NodeReplaceAllChildren extends NodeAppendChild {
/**
* Trivial constructor.
*
* @param parent will become the parent of the appended Element.
* @param child the Element to be appended.
*/
public NodeReplaceAllChildren(Element parent, Element child) {
super(parent, child, null, null);
}
/**
* Full constructor.
*
* @param parent Parent node to append the child to
* @param child Child element
* @param plot Plot to register the ID (may be {@code null})
* @param id ID to register (may be {@code null}, requires plot to be given)
*/
public NodeReplaceAllChildren(Element parent, Element child, SVGPlot plot, String id) {
super(parent, child, plot, id);
}
@Override
public void run() {
// remove all existing children.
while(parent.hasChildNodes()) {
parent.removeChild(parent.getLastChild());
}
super.run();
}
}
NodeReplaceByID.java 0000664 0000000 0000000 00000003665 12657057427 0035553 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/batikutil package de.lmu.ifi.dbs.elki.visualization.batikutil;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.w3c.dom.Element;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGPlot;
/**
* This helper class will replace a node in an SVG plot. This is a Runnable to
* be put on the update queue.
*
* @author Erich Schubert
* @since 0.2
*/
public class NodeReplaceByID implements Runnable {
/**
* Plot to work in.
*/
private SVGPlot plot;
/**
* ID of element to replace.
*/
private String id;
/**
* Replacement element.
*/
private Element newe;
/**
* Setup a SVG node replacement.
*
* @param newe New element
* @param plot SVG plot to process
* @param id Node ID to replace
*/
public NodeReplaceByID(Element newe, SVGPlot plot, String id) {
super();
this.newe = newe;
this.plot = plot;
this.id = id;
}
@Override
public void run() {
Element olde = plot.getIdElement(id);
if(olde != null) {
olde.getParentNode().replaceChild(newe, olde);
plot.putIdElement(id, newe);
}
// Note: no warning if it is not possible!
}
}
NodeSubstitute.java 0000664 0000000 0000000 00000003231 12657057427 0035630 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/batikutil package de.lmu.ifi.dbs.elki.visualization.batikutil;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.w3c.dom.Element;
/**
* This helper class will replace a node in an SVG plot. This is a Runnable to
* be put on the update queue.
*
* @author Erich Schubert
* @since 0.2
*/
public class NodeSubstitute implements Runnable {
/**
* Existing element to replace.
*/
private Element prev;
/**
* Replacement element.
*/
private Element newe;
/**
* Setup a SVG node replacement.
*
* @param prev Existing element
* @param newe New element
*/
public NodeSubstitute(Element prev, Element newe) {
super();
this.prev = prev;
this.newe = newe;
}
@Override
public void run() {
prev.getParentNode().replaceChild(newe, prev);
// Note: no warning if it is not possible!
}
}
RemoveCSSClass.java 0000775 0000000 0000000 00000003151 12657057427 0035447 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/batikutil package de.lmu.ifi.dbs.elki.visualization.batikutil;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.w3c.dom.Element;
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventListener;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
/**
* Remove a CSS class to the event target.
*
* @author Erich Schubert
* @since 0.2
*
*/
public class RemoveCSSClass implements EventListener {
/**
* Class to set
*/
private String cssclass;
/**
* Constructor
* @param cssclass class to set
*/
public RemoveCSSClass(String cssclass) {
super();
this.cssclass = cssclass;
}
/**
* Event handler
*/
@Override
public void handleEvent(Event evt) {
Element e = (Element) evt.getTarget();
SVGUtil.removeCSSClass(e, cssclass);
}
} ThumbnailRegistryEntry.java 0000664 0000000 0000000 00000015673 12657057427 0037362 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/batikutil package de.lmu.ifi.dbs.elki.visualization.batikutil;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import gnu.trove.iterator.TIntObjectIterator;
import gnu.trove.map.TIntObjectMap;
import gnu.trove.map.hash.TIntObjectHashMap;
import java.awt.image.RenderedImage;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.util.Iterator;
import org.apache.batik.ext.awt.image.GraphicsUtil;
import org.apache.batik.ext.awt.image.renderable.Filter;
import org.apache.batik.ext.awt.image.renderable.RedRable;
import org.apache.batik.ext.awt.image.spi.AbstractRegistryEntry;
import org.apache.batik.ext.awt.image.spi.ImageTagRegistry;
import org.apache.batik.ext.awt.image.spi.MagicNumberRegistryEntry;
import org.apache.batik.ext.awt.image.spi.URLRegistryEntry;
import org.apache.batik.svggen.ErrorConstants;
import org.apache.batik.util.ParsedURL;
import org.apache.batik.util.ParsedURLData;
import org.apache.batik.util.ParsedURLProtocolHandler;
import de.lmu.ifi.dbs.elki.logging.Logging;
/**
* Access images via an internal image registry.
*
* @author Erich Schubert
* @since 0.5.0
*/
public class ThumbnailRegistryEntry extends AbstractRegistryEntry implements URLRegistryEntry, ParsedURLProtocolHandler {
/**
* ELKI internal thumbnail protocol id.
*/
public static final String INTERNAL_PROTOCOL = "thumb";
/**
* ELKI internal thumbnail protocol prefix
*/
public static final String INTERNAL_PREFIX = INTERNAL_PROTOCOL + ":";
/**
* Mime type
*/
public static final String INTERNAL_MIME_TYPE = "internal/thumb";
/**
* The priority of this entry.
*/
public static final float PRIORITY = 1 * MagicNumberRegistryEntry.PRIORITY;
/**
* The logger class.
*/
private static final Logging LOG = Logging.getLogger(ThumbnailRegistryEntry.class);
/**
* The image cache.
*/
private static final TIntObjectMap> images = new TIntObjectHashMap<>();
/**
* Object counter
*/
private static int counter = 1;
/**
* Constructor.
*
* Note: there will usually be two instances created. One for handling the
* image type, one for the URL handling. This is ok.
*/
public ThumbnailRegistryEntry() {
super("Internal", PRIORITY, new String[0], new String[] { INTERNAL_MIME_TYPE });
if(LOG.isDebuggingFiner()) {
LOG.debugFiner("Registry initialized.");
}
}
/**
* Put an image into the repository (note: the repository is only keeping a
* weak reference!)
*
* @param img Image to put
* @return Key
*/
public static int registerImage(RenderedImage img) {
synchronized(images) {
int key = counter;
counter++;
assert (images.get(key) == null);
images.put(key, new SoftReference<>(img));
// Reorganize map, purge old entries
if(counter % 50 == 49) {
for(TIntObjectIterator> iter = images.iterator(); iter.hasNext();) {
iter.advance();
if(iter.value() == null || iter.value().get() == null) {
iter.remove();
}
}
}
if(LOG.isDebuggingFiner()) {
LOG.debugFiner("Registered image: " + key);
}
return key;
}
}
@Override
public boolean isCompatibleURL(ParsedURL url) {
// logger.warning("isCompatible " + url.toString());
return isCompatibleURLStatic(url);
}
/**
* Test for a compatible URL.
*
* @param url URL
* @return Success code
*/
public static boolean isCompatibleURLStatic(ParsedURL url) {
return url.getProtocol().equals(INTERNAL_PROTOCOL);
}
@Override
public Filter handleURL(ParsedURL url, boolean needRawData) {
Filter ret = handleURL(url);
if(ret != null) {
return ret;
}
// Image not found in registry.
return ImageTagRegistry.getBrokenLinkImage(ThumbnailRegistryEntry.this, ErrorConstants.ERR_IMAGE_DIR_DOES_NOT_EXIST, new Object[0]);
}
/**
* Statically handle the URL access.
*
* @param url URL to access
* @return Image, or null
*/
public static Filter handleURL(ParsedURL url) {
if(LOG.isDebuggingFiner()) {
LOG.debugFiner("handleURL " + url.toString());
}
if(!isCompatibleURLStatic(url)) {
return null;
}
int id;
try {
id = Integer.parseInt(url.getPath());
}
catch(NumberFormatException e) {
return null;
}
SoftReference ref = images.get(id);
if(ref != null) {
RenderedImage ri = ref.get();
if(ri == null) {
LOG.warning("Referenced image has expired from the cache!");
}
else {
return new RedRable(GraphicsUtil.wrap(ri));
}
}
// Image not found in registry.
return null;
}
/**
* URL representation for internal URLs.
*
* @author Erich Schubert
*
* @apiviz.exclude
*/
class InternalParsedURLData extends ParsedURLData {
/**
* Constructor.
*/
public InternalParsedURLData(String id) {
super();
this.protocol = INTERNAL_PROTOCOL;
this.contentType = INTERNAL_MIME_TYPE;
this.path = id;
}
@Override
public String getContentType(String userAgent) {
return INTERNAL_MIME_TYPE;
}
@Override
public boolean complete() {
return true;
}
@SuppressWarnings("rawtypes")
@Override
public InputStream openStream(String userAgent, Iterator mimeTypes) throws IOException {
// Return null, since we don't want to use streams.
return null;
}
}
@Override
public ParsedURLData parseURL(String urlStr) {
if(LOG.isDebuggingFinest()) {
LOG.debugFinest("parseURL: " + urlStr);
}
if(urlStr.startsWith(INTERNAL_PREFIX)) {
InternalParsedURLData ret = new InternalParsedURLData(urlStr.substring(INTERNAL_PREFIX.length()));
return ret;
}
return null;
}
@Override
public ParsedURLData parseURL(ParsedURL basepurl, String urlStr) {
// Won't happen in a relative way anyway, and is not particularly
// supported (as the objects might be dropped from the cache)
return parseURL(urlStr);
}
@Override
public String getProtocolHandled() {
return INTERNAL_PROTOCOL;
}
} ThumbnailTranscoder.java 0000664 0000000 0000000 00000003722 12657057427 0036624 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/batikutil package de.lmu.ifi.dbs.elki.visualization.batikutil;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.awt.image.BufferedImage;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.ImageTranscoder;
/**
* Transcode images to in-memory thumbnails.
*
* @author Erich Schubert
* @since 0.2
*/
public class ThumbnailTranscoder extends ImageTranscoder {
/**
* Last image produced.
*/
private BufferedImage lastimg;
/**
* Constructor.
*/
public ThumbnailTranscoder() {
super();
hints.put(KEY_FORCE_TRANSPARENT_WHITE, Boolean.FALSE);
}
@Override
public BufferedImage createImage(int width, int height) {
return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
}
/**
* Output will be ignored!
*/
@Override
public void writeImage(BufferedImage img, TranscoderOutput output) throws TranscoderException {
lastimg = img;
}
/**
* Get the latest image produced.
*
* @return the last image produced
*/
public BufferedImage getLastImage() {
return lastimg;
}
} package-info.java 0000775 0000000 0000000 00000001751 12657057427 0035203 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/batikutil /**
*
Commonly used functionality useful for Apache Batik.
*
*/
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.lmu.ifi.dbs.elki.visualization.batikutil; elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/colors/ 0000775 0000000 0000000 00000000000 12657057427 0031375 5 ustar 00root root 0000000 0000000 ColorLibrary.java 0000775 0000000 0000000 00000004662 12657057427 0034577 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/colors package de.lmu.ifi.dbs.elki.visualization.colors;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
/**
* Color scheme interface
*
* @author Erich Schubert
* @since 0.2
*/
public interface ColorLibrary {
/**
* List of line colors
*/
final static String COLOR_LINE_COLORS = "line.colors";
/**
* Named color for the page background
*/
final static String COLOR_PAGE_BACKGROUND = "page.background";
/**
* Named color for a typical axis
*/
final static String COLOR_AXIS_LINE = "axis.line";
/**
* Named color for a typical axis tick mark
*/
final static String COLOR_AXIS_TICK = "axis.tick";
/**
* Named color for a typical axis tick mark
*/
final static String COLOR_AXIS_MINOR_TICK = "axis.tick.minor";
/**
* Named color for a typical axis label
*/
final static String COLOR_AXIS_LABEL = "axis.label";
/**
* Named color for the background of the key box
*/
final static String COLOR_KEY_BACKGROUND = "key.background";
/**
* Named color for a label in the key part
*/
final static String COLOR_KEY_LABEL = "key.label";
/**
* Background color for plot area
*/
final static String COLOR_PLOT_BACKGROUND = "plot.background";
/**
* Return the number of native colors available. These are guaranteed to be
* unique.
*
* @return number of native colors
*/
public int getNumberOfNativeColors();
/**
* Return the i'th color.
*
* @param index color index
* @return color in hexadecimal notation (#aabbcc) or color name ("red") as
* valid in CSS and SVG.
*/
public String getColor(int index);
}
ListBasedColorLibrary.java 0000664 0000000 0000000 00000003377 12657057427 0036371 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/colors package de.lmu.ifi.dbs.elki.visualization.colors;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
/**
* Color library using the color names from a list.
*
* @author Erich Schubert
* @since 0.3
*/
public class ListBasedColorLibrary implements ColorLibrary {
/**
* Array of color names.
*/
private String[] colors;
/**
* Color scheme name
*/
private String name;
/**
* Constructor without a properties file name.
*
* @param colors Colors
* @param name Library name
*/
public ListBasedColorLibrary(String[] colors, String name) {
this.colors = colors;
this.name = name;
}
@Override
public String getColor(int index) {
return colors[Math.abs(index) % colors.length];
}
@Override
public int getNumberOfNativeColors() {
return colors.length;
}
/**
* Get the color scheme name.
*
* @return the name
*/
protected String getName() {
return name;
}
} package-info.java 0000775 0000000 0000000 00000001721 12657057427 0034511 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/colors /**
*
Color scheme handling for ELKI.
*
*/
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.lmu.ifi.dbs.elki.visualization.colors; elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/css/ 0000775 0000000 0000000 00000000000 12657057427 0030664 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/css/CSSClass.java 0000775 0000000 0000000 00000016576 12657057427 0033167 0 ustar 00root root 0000000 0000000 package de.lmu.ifi.dbs.elki.visualization.css;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import de.lmu.ifi.dbs.elki.utilities.pairs.Pair;
/**
* Class representing a single CSS class.
*
* @author Erich Schubert
* @since 0.2
*/
public class CSSClass {
/**
* CSS class name
*/
private String name;
/**
* Actual CSS statements
*/
private Collection> statements;
/**
* Owner.
*/
private WeakReference owner;
/**
* Full constructor
*
* @param owner Class owner (to detect conflicts)
* @param name Class name
* @param statements Collection of CSS statements
*/
public CSSClass(Object owner, String name, Collection> statements) {
this.owner = new WeakReference<>(owner);
this.name = name;
this.statements = statements;
if (!checkName(name)) {
throw new InvalidCSS("Given name is not a valid CSS class name.");
}
if (this.statements != null) {
if (!checkCSSStatements(this.statements)) {
throw new InvalidCSS("Invalid statement in CSS class "+name);
}
} else {
// if needed, use an array list.
this.statements = new ArrayList<>();
}
}
/**
* Simplified constructor, empty statements list.
*
* @param owner Class owner.
* @param name Class name.
*/
public CSSClass(Object owner, String name) {
this(owner, name, (Collection>) null);
}
/**
* Cloning constructor
*
* @param owner Class owner.
* @param name Class name.
* @param other Class to clone
*/
public CSSClass(Object owner, String name, CSSClass other) {
this(owner, name, new ArrayList<>(other.statements));
}
/**
* Verify that the name is an admissible CSS class name.
*
* TODO: implement.
*
* @param name name to use
* @return true if valid CSS class name
*/
public static boolean checkName(String name) {
// TODO: implement a sanity check - regexp?
return (name != null);
}
/**
* Return a sanitized version of the given string.
*
* TODO: implement extensive checks.
*
* @param name name to sanitize
* @return Sanitized version.
*/
public static String sanitizeName(String name) {
// TODO: implement a sanitization - regexp?
return name;
}
/**
* Validate a single CSS statement.
*
* TODO: implement extensive checks.
*
* @param key Key
* @param value Value
* @return true if valid statement.
*/
public static boolean checkCSSStatement(String key, String value) {
// TODO: implement more extensive checks!
return (key != null) && (value != null);
}
/**
* Validate a set of CSS statements.
*
* TODO: checks are currently not very extensive.
*
* @param statements Statements to check
* @return true if valid
*/
public static boolean checkCSSStatements(Collection> statements) {
for (Pair pair : statements) {
if (!checkCSSStatement(pair.getFirst(), pair.getSecond())) {
return false;
}
}
return true;
}
/**
* Get the class name.
*
* @return class name.
*/
public String getName() {
return this.name;
}
/**
* Set the class name.
*
* @param name new class name.
*/
public void setName(String name) {
this.name = name;
}
/**
* Get class owner.
*
* @return class owner.
*/
public Object getOwner() {
return this.owner.get();
}
/**
* Get the current value of a particular CSS statement.
*
* @param key statement key.
* @return current value or null.
*/
public String getStatement(String key) {
for (Pair pair : statements) {
if (pair.getFirst().equals(key)) {
return pair.getSecond();
}
}
return null;
}
/**
* Get read-only collection access to all statements.
*
* @return Collection
*/
public Collection> getStatements() {
return Collections.unmodifiableCollection(statements);
}
/**
* Set a CSS statement.
*
* @param key Statement key.
* @param value Value or null (to unset)
*/
public void setStatement(String key, String value) {
if (value != null) {
if (!checkCSSStatement(key, value)) {
throw new InvalidCSS("Invalid CSS statement.");
}
}
for (Pair pair : statements) {
if (pair.getFirst().equals(key)) {
if (value != null) {
pair.setSecond(value);
} else {
statements.remove(pair);
}
return;
}
}
if (value != null) {
statements.add(new Pair<>(key, value));
}
}
/**
* Set a CSS statement.
*
* @param key Statement key.
* @param value Value
*/
public void setStatement(String key, int value) {
setStatement(key, Integer.toString(value));
}
/**
* Set a CSS statement.
*
* @param key Statement key.
* @param value Value
*/
public void setStatement(String key, double value) {
setStatement(key, Double.toString(value));
}
/**
* Remove a CSS statement.
*
* @param key Statement key.
*/
public void removeStatement(String key) {
setStatement(key, null);
}
/**
* Append CSS definition to a stream
*
* @param buf String buffer to append to.
*/
public void appendCSSDefinition(StringBuilder buf) {
buf.append("\n.");
buf.append(name);
buf.append('{');
for (Pair pair : statements) {
buf.append(pair.getFirst());
buf.append(':');
buf.append(pair.getSecond());
buf.append(";\n");
}
buf.append("}\n");
}
/**
* Exception class thrown when encountering invalid CSS.
*
* @apiviz.exclude
*/
public class InvalidCSS extends RuntimeException {
/**
* Constructor. See {@link RuntimeException}.
*
* @param msg Error message.
*/
public InvalidCSS(String msg) {
super(msg);
}
/**
* Serial version UID.
*/
private static final long serialVersionUID = 3130536799704124363L;
}
/**
* Render CSS class to inline formatting
*
* @return string rendition of CSS for inline use
*/
public String inlineCSS() {
StringBuilder buf = new StringBuilder();
for (Pair pair : statements) {
buf.append(pair.getFirst());
buf.append(':');
buf.append(pair.getSecond());
buf.append(';');
}
return buf.toString();
}
} CSSClassManager.java 0000775 0000000 0000000 00000013730 12657057427 0034370 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/css package de.lmu.ifi.dbs.elki.visualization.css;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.Collection;
import java.util.HashMap;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
/**
* Manager class to track CSS classes used in a particular SVG document.
*
* @author Erich Schubert
* @since 0.2
*
* @apiviz.has de.lmu.ifi.dbs.elki.visualization.css.CSSClass
*/
public class CSSClassManager {
/**
* Store the contained CSS classes.
*/
private HashMap store = new HashMap<>();
/**
* Add a single class to the map.
*
* @param clss new CSS class
* @return existing (old) class
* @throws CSSNamingConflict when a class of the same name but different owner object exists.
*/
public CSSClass addClass(CSSClass clss) throws CSSNamingConflict {
CSSClass existing = store.get(clss.getName());
if (existing != null && existing.getOwner() != null && existing.getOwner() != clss.getOwner()) {
throw new CSSNamingConflict("CSS class naming conflict between "+clss.getOwner().toString()+" and "+existing.getOwner().toString());
}
return store.put(clss.getName(), clss);
}
/**
* Remove a single CSS class from the map.
* Note that classes are removed by reference, not by name!
*
* @param clss Class to remove
*/
public synchronized void removeClass(CSSClass clss) {
CSSClass existing = store.get(clss.getName());
if (existing == clss) {
store.remove(existing.getName());
}
}
/**
* Retrieve a single class by name and owner
*
* @param name Class name
* @param owner Class owner
* @return existing (old) class
* @throws CSSNamingConflict if an owner was specified and doesn't match
*/
public CSSClass getClass(String name, Object owner) throws CSSNamingConflict {
CSSClass existing = store.get(name);
// Not found.
if (existing == null) {
return null;
}
// Different owner
if (owner != null && existing.getOwner() != owner) {
throw new CSSNamingConflict("CSS class naming conflict between "+owner.toString()+" and "+existing.getOwner().toString());
}
return existing;
}
/**
* Retrieve a single class by name only
*
* @param name CSS class name
* @return existing (old) class
*/
public CSSClass getClass(String name) {
return store.get(name);
}
/**
* Check if a name is already used in the classes.
*
* @param name CSS class name
* @return true if the class name is already used.
*/
public boolean contains(String name) {
return store.containsKey(name);
}
/**
* Serialize managed CSS classes to rule file.
*
* @param buf String buffer
*/
public void serialize(StringBuilder buf) {
for (CSSClass clss : store.values()) {
clss.appendCSSDefinition(buf);
}
}
/**
* Get all CSS classes in this manager.
*
* @return CSS classes.
*/
public Collection getClasses() {
return store.values();
}
/**
* Check whether or not CSS classes of two plots can be merged
*
* @param other Other class
* @return true if able to merge
*/
public boolean testMergeable(CSSClassManager other) {
for (CSSClass clss : other.getClasses()) {
CSSClass existing = store.get(clss.getName());
// Check for a naming conflict.
if (existing != null && existing.getOwner() != null && clss.getOwner() != null && existing.getOwner() != clss.getOwner()) {
return false;
}
}
return true;
}
/**
* Merge CSS classes, for example to merge two plots.
*
* @param other Other class to merge with
* @return success code
* @throws CSSNamingConflict If there is a naming conflict.
*/
public boolean mergeCSSFrom(CSSClassManager other) throws CSSNamingConflict {
for (CSSClass clss : other.getClasses()) {
this.addClass(clss);
}
return true;
}
/**
* Class to signal a CSS naming conflict.
*
* @apiviz.exclude
*/
public class CSSNamingConflict extends Exception {
/**
* Serial version UID
*/
private static final long serialVersionUID = 4163822727195636747L;
/**
* Exception to signal a CSS naming conflict.
*
* @param msg Exception message
*/
public CSSNamingConflict(String msg) {
super(msg);
}
}
/**
* Update the text contents of an existing style element.
*
* @param document Document element (factory)
* @param style Style element
*/
public void updateStyleElement(Document document, Element style) {
StringBuilder buf = new StringBuilder();
serialize(buf);
Text cont = document.createTextNode(buf.toString());
while (style.hasChildNodes()) {
style.removeChild(style.getFirstChild());
}
style.appendChild(cont);
}
/**
* Make a (filled) CSS style element for the given document.
*
* @param document Document
* @return Style element
*/
public Element makeStyleElement(Document document) {
Element style = SVGUtil.makeStyleElement(document);
updateStyleElement(document, style);
return style;
}
}
package-info.java 0000775 0000000 0000000 00000001715 12657057427 0034003 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/css /**
*
Managing CSS styles / classes.
*
*/
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.lmu.ifi.dbs.elki.visualization.css; elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/gui/ 0000775 0000000 0000000 00000000000 12657057427 0030660 5 ustar 00root root 0000000 0000000 ResultWindow.java 0000664 0000000 0000000 00000043276 12657057427 0034126 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/gui package de.lmu.ifi.dbs.elki.visualization.gui;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Collection;
import javax.swing.ImageIcon;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.SwingUtilities;
import org.apache.batik.swing.svg.GVTTreeBuilderAdapter;
import org.apache.batik.swing.svg.GVTTreeBuilderEvent;
import de.lmu.ifi.dbs.elki.KDDTask;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.result.Result;
import de.lmu.ifi.dbs.elki.result.ResultHierarchy;
import de.lmu.ifi.dbs.elki.result.ResultListener;
import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.Hierarchy;
import de.lmu.ifi.dbs.elki.visualization.VisualizationItem;
import de.lmu.ifi.dbs.elki.visualization.VisualizationListener;
import de.lmu.ifi.dbs.elki.visualization.VisualizationMenuAction;
import de.lmu.ifi.dbs.elki.visualization.VisualizationMenuToggle;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTree;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.batikutil.JSVGSynchronizedCanvas;
import de.lmu.ifi.dbs.elki.visualization.batikutil.LazyCanvasResizer;
import de.lmu.ifi.dbs.elki.visualization.gui.detail.DetailView;
import de.lmu.ifi.dbs.elki.visualization.gui.overview.DetailViewSelectedEvent;
import de.lmu.ifi.dbs.elki.visualization.gui.overview.OverviewPlot;
import de.lmu.ifi.dbs.elki.visualization.gui.overview.PlotItem;
import de.lmu.ifi.dbs.elki.visualization.projections.Projection;
import de.lmu.ifi.dbs.elki.visualization.savedialog.SVGSaveDialog;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGPlot;
/**
* Swing window to manage a particular result visualization.
*
* Yes, this is very basic and ad-hoc. Feel free to contribute something more
* advanced to ELKI!
*
* @author Erich Schubert
* @author Remigius Wojdanowski
* @since 0.3
*
* @apiviz.composedOf JSVGSynchronizedCanvas
* @apiviz.composedOf OverviewPlot
* @apiviz.composedOf SelectionTableWindow
* @apiviz.composedOf SVGSaveDialog
* @apiviz.composedOf LazyCanvasResizer
* @apiviz.has VisualizerContext
* @apiviz.uses DetailView oneway
* @apiviz.uses DetailViewSelectedEvent oneway - - reacts to
*/
public class ResultWindow extends JFrame implements ResultListener, VisualizationListener {
/**
* Serial version
*/
private static final long serialVersionUID = 1L;
/**
* Get a logger for this class.
*/
private static final Logging LOG = Logging.getLogger(ResultWindow.class);
/**
* Dynamic menu.
*
* @apiviz.exclude
*/
public class DynamicMenu {
/**
* Menubar component
*/
private JMenuBar menubar;
/**
* File menu.
*/
private JMenu filemenu;
/**
* The "Overview" button, which goes to the overview view.
*/
private JMenuItem overviewItem;
/**
* The "Quit" button, to close the application.
*/
private JMenuItem quitItem;
/**
* The "Export" button, to save the image
*/
private JMenuItem exportItem;
/**
* The "tabular edit" item.
*/
private JMenuItem editItem;
/**
* The "Visualizers" button, to enable/disable visualizers
*/
private JMenu visualizersMenu;
/**
* Simplify the menu.
*/
protected boolean simplify = true;
/**
* Constructor.
*/
public DynamicMenu() {
menubar = new JMenuBar();
filemenu = new JMenu("File");
filemenu.setMnemonic(KeyEvent.VK_F);
// setup buttons
if(!single) {
overviewItem = new JMenuItem("Open Overview");
overviewItem.setMnemonic(KeyEvent.VK_O);
overviewItem.setEnabled(false);
overviewItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
showOverview();
}
});
filemenu.add(overviewItem);
}
exportItem = new JMenuItem("Export Plot");
exportItem.setMnemonic(KeyEvent.VK_E);
exportItem.setEnabled(false);
exportItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
saveCurrentPlot();
}
});
filemenu.add(exportItem);
editItem = new JMenuItem("Table View/Edit");
editItem.setMnemonic(KeyEvent.VK_T);
editItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
showTableView();
}
});
// FIXME: re-add when it is working again.
// filemenu.add(editItem);
quitItem = new JMenuItem("Quit");
quitItem.setMnemonic(KeyEvent.VK_Q);
quitItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
close();
}
});
filemenu.add(quitItem);
menubar.add(filemenu);
visualizersMenu = new JMenu("Visualizers");
visualizersMenu.setMnemonic(KeyEvent.VK_V);
menubar.add(visualizersMenu);
}
/**
* Update the visualizer menus.
*/
protected synchronized void updateVisualizerMenus() {
Projection proj = null;
if(svgCanvas.getPlot() instanceof DetailView) {
PlotItem item = ((DetailView) svgCanvas.getPlot()).getPlotItem();
proj = item.proj;
}
menubar.removeAll();
menubar.add(filemenu);
ResultHierarchy hier = context.getHierarchy();
Hierarchy vistree = context.getVisHierarchy();
Result start = context.getBaseResult();
ArrayList items = new ArrayList<>();
if(start == null) {
for(Hierarchy.Iter iter = hier.iterAll(); iter.valid(); iter.advance()) {
if(hier.numParents(iter.get()) == 0) {
recursiveBuildMenu(items, iter.get(), hier, vistree, proj);
}
}
}
else {
for(Hierarchy.Iter iter = hier.iterChildren(start); iter.valid(); iter.advance()) {
recursiveBuildMenu(items, iter.get(), hier, vistree, proj);
}
}
// Add all items.
for(JMenuItem item : items) {
menubar.add(item);
}
menubar.revalidate();
menubar.repaint();
}
private void recursiveBuildMenu(Collection items, Object r, ResultHierarchy hier, Hierarchy vistree, Projection proj) {
// Make a submenu for this element
final String nam;
if(r instanceof Result) {
nam = ((Result) r).getLongName();
}
else if(r instanceof VisualizationItem) {
nam = ((VisualizationItem) r).getMenuName();
}
else {
return;
}
ArrayList subitems = new ArrayList<>();
// Add menus for any child results
if(r instanceof Result) {
for(Hierarchy.Iter iter = hier.iterChildren((Result) r); iter.valid(); iter.advance()) {
recursiveBuildMenu(subitems, iter.get(), hier, vistree, proj);
}
}
// Add visualizers:
for(Hierarchy.Iter iter = vistree.iterChildren(r); iter.valid(); iter.advance()) {
recursiveBuildMenu(subitems, iter.get(), hier, vistree, proj);
}
// Item for the visualizer
JMenuItem item = null;
if(proj == null) {
item = makeMenuItemForVisualizer(r);
}
else {
// Only include items that belong to different projections:
for(Hierarchy.Iter iter = vistree.iterAncestorsSelf(r); iter.valid(); iter.advance()) {
if(iter.get() == proj.getProjector()) {
item = makeMenuItemForVisualizer(r);
break;
}
}
}
final int numchild = subitems.size();
if(numchild == 0) {
if(item != null) {
items.add(item);
}
return;
}
if(simplify && numchild == 1) {
JMenuItem a = subitems.get(0);
if(a instanceof JMenu) {
if(nam != null) {
a.setText(nam + " " + a.getText());
}
items.add(a);
return;
}
}
JMenu submenu = new JMenu((nam != null) ? nam : "unnamed");
if(item != null) {
submenu.add(item);
}
for(JMenuItem subitem : subitems) {
submenu.add(subitem);
}
items.add(submenu);
}
private JMenuItem makeMenuItemForVisualizer(Object r) {
if(r instanceof VisualizationMenuAction) {
final VisualizationMenuAction action = (VisualizationMenuAction) r;
JMenuItem visItem = new JMenuItem(action.getMenuName());
visItem.setEnabled(action.enabled());
visItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
action.activate();
}
});
return visItem;
}
if(r instanceof VisualizationMenuToggle) {
final VisualizationMenuToggle toggle = (VisualizationMenuToggle) r;
final JCheckBoxMenuItem visItem = new JCheckBoxMenuItem(toggle.getMenuName(), toggle.active());
visItem.setEnabled(toggle.enabled());
visItem.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
toggle.toggle();
}
});
return visItem;
}
if(!(r instanceof VisualizationTask)) {
return null;
}
final VisualizationTask v = (VisualizationTask) r;
JMenuItem item;
// Currently enabled?
final String name = v.getMenuName();
boolean enabled = v.visible;
boolean istool = v.tool;
if(!istool) {
final JCheckBoxMenuItem visItem = new JCheckBoxMenuItem(name, enabled);
visItem.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
VisualizationTree.setVisible(context, v, visItem.getState());
}
});
item = visItem;
}
else {
final JRadioButtonMenuItem visItem = new JRadioButtonMenuItem(name, enabled);
visItem.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
VisualizationTree.setVisible(context, v, visItem.isSelected());
}
});
item = visItem;
}
return item;
}
/**
* Get the menu bar component.
*
* @return Menu bar component
*/
public JMenuBar getMenuBar() {
return menubar;
}
/**
* Enable / disable the overview menu.
*
* @param b Flag
*/
public void enableOverview(boolean b) {
if(overviewItem != null) {
overviewItem.setEnabled(b);
}
}
/**
* Enable / disable the export menu.
*
* @param b Flag
*/
public void enableExport(boolean b) {
exportItem.setEnabled(b);
}
}
private DynamicMenu menubar;
/**
* The SVG canvas.
*/
private JSVGSynchronizedCanvas svgCanvas;
/**
* The overview plot.
*/
private OverviewPlot overview;
/**
* Visualizer context
*/
protected VisualizerContext context;
/**
* Currently selected subplot.
*/
private DetailView currentSubplot = null;
/**
* Single view mode. No overview / detail view split
*/
private boolean single = false;
/**
* Constructor.
*
* @param title Window title
* @param context Visualizer context
* @param single Single visualization mode
*/
public ResultWindow(String title, VisualizerContext context, boolean single) {
super(title);
this.context = context;
this.single = single;
// close handler
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// ELKI icon
try {
setIconImage(new ImageIcon(KDDTask.class.getResource("elki-icon.png")).getImage());
}
catch(Exception e) {
// Ignore - icon not found is not fatal.
}
// Create a panel and add the button, status label and the SVG canvas.
final JPanel panel = new JPanel(new BorderLayout());
menubar = new DynamicMenu();
panel.add("North", menubar.getMenuBar());
svgCanvas = new JSVGSynchronizedCanvas();
panel.add("Center", svgCanvas);
this.getContentPane().add(panel);
overview = new OverviewPlot(context, single);
// when a subplot is clicked, show the selected subplot.
overview.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if(e instanceof DetailViewSelectedEvent) {
showSubplot((DetailViewSelectedEvent) e);
}
if(OverviewPlot.OVERVIEW_REFRESHING == e.getActionCommand()) {
if(currentSubplot == null) {
showPlot(null);
}
}
if(OverviewPlot.OVERVIEW_REFRESHED == e.getActionCommand()) {
if(currentSubplot == null) {
showOverview();
}
}
}
});
// handle screen size
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
overview.screenwidth = dim.width;
overview.screenheight = dim.height;
// Maximize.
this.setSize(dim.width - 50, dim.height - 50);
this.setExtendedState(JFrame.MAXIMIZED_BOTH);
// resize listener
final LazyCanvasResizer listener = new LazyCanvasResizer(this, 0.1) {
@Override
public void executeResize(double newratio) {
ResultWindow.this.handleResize(newratio);
}
};
this.addComponentListener(listener);
svgCanvas.addGVTTreeBuilderListener(new GVTTreeBuilderAdapter() {
@Override
public void gvtBuildCompleted(GVTTreeBuilderEvent arg0) {
// Supposedly in Swing thread.
menubar.updateVisualizerMenus();
}
});
context.addResultListener(this);
context.addVisualizationListener(this);
overview.initialize(listener.getCurrentRatio());
}
@Override
public void dispose() {
context.removeResultListener(this);
context.removeVisualizationListener(this);
svgCanvas.setPlot(null);
overview.destroy();
if(currentSubplot != null) {
currentSubplot.dispose();
currentSubplot = null;
}
super.dispose();
}
/**
* Close the visualizer window.
*/
protected void close() {
this.setVisible(false);
this.dispose();
}
/**
* Navigate to the overview plot.
*/
public void showOverview() {
if(currentSubplot != null) {
currentSubplot.destroy();
}
currentSubplot = null;
showPlot(overview.getPlot());
}
/**
* Navigate to a subplot.
*
* @param e
*/
protected void showSubplot(DetailViewSelectedEvent e) {
if(!single) {
currentSubplot = e.makeDetailView();
showPlot(currentSubplot);
}
}
/**
* Navigate to a particular plot.
*
* @param plot Plot to show.
*/
private void showPlot(final SVGPlot plot) {
if(svgCanvas.getPlot() instanceof DetailView) {
((DetailView) svgCanvas.getPlot()).destroy();
}
svgCanvas.setPlot(plot);
menubar.enableOverview(plot != overview.getPlot());
menubar.enableExport(plot != null);
updateVisualizerMenus();
}
/**
* Save/export the current plot.
*/
protected void saveCurrentPlot() {
final SVGPlot currentPlot = svgCanvas.getPlot();
if(currentPlot == null) {
LOG.warning("saveCurrentPlot() called without a visible plot!");
return;
}
SVGSaveDialog.showSaveDialog(currentPlot, 512, 512);
}
/**
* Show a tabular view
*/
protected void showTableView() {
(new SelectionTableWindow(context)).setVisible(true);
}
/**
* Refresh the overview
*/
protected void update() {
updateVisualizerMenus();
if(currentSubplot != null) {
showPlot(currentSubplot);
}
overview.lazyRefresh();
}
/**
* Handle a resize event.
*
* @param newratio New window size ratio.
*/
protected void handleResize(double newratio) {
if(currentSubplot == null) {
ResultWindow.this.overview.setRatio(newratio);
}
}
@Override
public void resultAdded(Result child, Result parent) {
updateVisualizerMenus();
}
@Override
public void resultChanged(Result current) {
updateVisualizerMenus();
}
@Override
public void resultRemoved(Result child, Result parent) {
updateVisualizerMenus();
}
@Override
public void visualizationChanged(VisualizationItem item) {
updateVisualizerMenus();
}
/**
* Update visualizer menus, but only from Swing thread.
*/
private void updateVisualizerMenus() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
menubar.updateVisualizerMenus();
}
});
}
}
SelectionTableWindow.java 0000664 0000000 0000000 00000024356 12657057427 0035543 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/gui package de.lmu.ifi.dbs.elki.visualization.gui;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import de.lmu.ifi.dbs.elki.KDDTask;
import de.lmu.ifi.dbs.elki.data.ClassLabel;
import de.lmu.ifi.dbs.elki.data.SimpleClassLabel;
import de.lmu.ifi.dbs.elki.database.Database;
import de.lmu.ifi.dbs.elki.database.UpdatableDatabase;
import de.lmu.ifi.dbs.elki.database.datastore.DataStoreEvent;
import de.lmu.ifi.dbs.elki.database.datastore.DataStoreListener;
import de.lmu.ifi.dbs.elki.database.ids.ArrayModifiableDBIDs;
import de.lmu.ifi.dbs.elki.database.ids.DBIDArrayIter;
import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil;
import de.lmu.ifi.dbs.elki.database.ids.ModifiableDBIDs;
import de.lmu.ifi.dbs.elki.database.relation.ModifiableRelation;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.result.DBIDSelection;
import de.lmu.ifi.dbs.elki.result.Result;
import de.lmu.ifi.dbs.elki.result.ResultListener;
import de.lmu.ifi.dbs.elki.result.ResultUtil;
import de.lmu.ifi.dbs.elki.result.SelectionResult;
import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
/**
* Visualizes selected Objects in a JTable, objects can be selected, changed and
* deleted
*
* @author Heidi Kolb
* @author Erich Schubert
* @since 0.4.0
*/
// FIXME: INCOMPLETE TRANSITION TO MULTI-REPRESENTED DATA
public class SelectionTableWindow extends JFrame implements DataStoreListener, ResultListener {
/**
* A short name characterizing this Visualizer.
*/
private static final String NAME = "Selected data objects";
/**
* Serial version
*/
private static final long serialVersionUID = 1L;
/**
* The JTable
*/
private JTable table;
/**
* Button to close the window
*/
private JButton closeButton;
/**
* Button to delete the selected objects
*/
private JButton deleteButton;
/**
* The table model
*/
private DatabaseTableModel dotTableModel = new DatabaseTableModel();
/**
* The logger
*/
private static final Logging LOG = Logging.getLogger(SelectionTableWindow.class);
/**
* The DBIDs to display
*/
ArrayModifiableDBIDs dbids;
/**
* The database we use
*/
UpdatableDatabase database;
/**
* Class label representation
*/
ModifiableRelation crep;
/**
* Object label representation
*/
ModifiableRelation orep;
/**
* Our context
*/
final protected VisualizerContext context;
/**
* The actual visualization instance, for a single projection
*
* @param context The Context
*/
public SelectionTableWindow(VisualizerContext context) {
super(NAME);
// ELKI icon
try {
setIconImage(new ImageIcon(KDDTask.class.getResource("elki-icon.png")).getImage());
}
catch(Exception e) {
// Ignore - icon not found is not fatal.
}
this.context = context;
this.database = (UpdatableDatabase) ResultUtil.findDatabase(context.getHierarchy());
// FIXME: re-add labels
this.crep = null; //database.getClassLabelQuery();
this.orep = null; //database.getObjectLabelQuery();
updateFromSelection();
JPanel panel = new JPanel(new BorderLayout());
table = new JTable(dotTableModel);
// table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
JScrollPane pane = new JScrollPane(table);
panel.add(pane, BorderLayout.CENTER);
JPanel buttons = new JPanel();
panel.add(buttons, BorderLayout.SOUTH);
closeButton = new JButton("close");
closeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
dispose();
}
});
deleteButton = new JButton("delete");
deleteButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
handleDelete();
}
});
buttons.add(closeButton);
buttons.add(deleteButton);
setSize(500, 500);
add(panel);
setVisible(true);
setResizable(true);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// Listen for Selection and Database changes.
context.addResultListener(this);
context.addDataStoreListener(this);
}
@Override
public void dispose() {
context.removeDataStoreListener(this);
context.removeResultListener(this);
super.dispose();
}
/**
* Update our selection
*/
protected void updateFromSelection() {
DBIDSelection sel = context.getSelection();
if(sel != null) {
this.dbids = DBIDUtil.newArray(sel.getSelectedIds());
this.dbids.sort();
}
else {
this.dbids = DBIDUtil.newArray();
}
}
/**
* Handle delete.
* Delete the marked objects in the database.
*/
protected void handleDelete() {
ModifiableDBIDs todel = DBIDUtil.newHashSet();
ModifiableDBIDs remain = DBIDUtil.newHashSet(dbids);
DBIDArrayIter it = dbids.iter();
for(int row : table.getSelectedRows()) {
it.seek(row);
todel.add(it);
remain.remove(it);
}
// Unselect first ...
context.setSelection(new DBIDSelection(remain));
// Now delete them.
for(DBIDIter iter = todel.iter(); iter.valid(); iter.advance()) {
database.delete(iter);
}
}
/**
* View onto the database
*
* @author Erich Schubert
*
* @apiviz.exclude
*/
class DatabaseTableModel extends AbstractTableModel {
/**
* Serial version
*/
private static final long serialVersionUID = 1L;
@Override
public int getColumnCount() {
return 3; //RelationUtil.dimensionality(database) + 3;
}
@Override
public int getRowCount() {
return dbids.size();
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
DBIDRef id = dbids.iter().seek(rowIndex);
if(columnIndex == 0) {
return DBIDUtil.toString(id);
}
if(columnIndex == 1) {
return orep.get(id);
}
if(columnIndex == 2) {
return crep.get(id);
}
/*NV obj = database.get(id);
if(obj == null) {
return null;
}
return obj.getValue(columnIndex - 3 + 1);*/
return null;
}
@Override
public String getColumnName(int column) {
if(column == 0) {
return "DBID";
}
if(column == 1) {
return "Object label";
}
if(column == 2) {
return "Class label";
}
return "Dim " + (column - 3 + 1);
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
if(columnIndex == 0) {
return false;
}
return true;
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if(columnIndex == 0) {
LOG.warning("Tried to edit DBID, this is not allowed.");
return;
}
final DBIDRef id = dbids.iter().seek(rowIndex);
if(columnIndex == 1 && aValue instanceof String) {
orep.insert(id, (String) aValue);
}
if(columnIndex == 2 && aValue instanceof String) {
// FIXME: better class label handling!
SimpleClassLabel lbl = new SimpleClassLabel((String) aValue);
crep.insert(id, lbl);
}
if(!(aValue instanceof String)) {
LOG.warning("Was expecting a String value from the input element, got: " + aValue.getClass());
return;
}
throw new AbortException("FIXME: INCOMPLETE TRANSITION");
/* NV obj = database.get(id);
if(obj == null) {
logger.warning("Tried to edit removed object?");
return;
}
final int dimensionality = RelationUtil.dimensionality(database);
double[] vals = new double[dimensionality];
for(int d = 0; d < dimensionality; d++) {
if(d == columnIndex - 3) {
vals[d] = FormatUtil.parseDouble((String) aValue);
}
else {
vals[d] = obj.doubleValue(d + 1);
}
}
NV newobj = obj.newInstance(vals);
newobj.setID(id);
final Representation mrep = database.getMetadataQuery();
DatabaseObjectMetadata meta = mrep.get(id);
try {
database.delete(id);
database.insert(new Pair(newobj, meta));
}
catch(UnableToComplyException e) {
de.lmu.ifi.dbs.elki.logging.LoggingUtil.exception(e);
} */
// TODO: refresh wrt. range selection!
}
}
@Override
public void contentChanged(DataStoreEvent e) {
if (e.getInserts().isEmpty() && e.getRemovals().isEmpty() && !e.getUpdates().isEmpty()) {
// Updates only.
dotTableModel.fireTableDataChanged();
}
else {
dotTableModel.fireTableStructureChanged();
}
}
@Override
public void resultAdded(Result child, Result parent) {
// TODO Auto-generated method stub
}
@Override
public void resultRemoved(Result child, Result parent) {
// TODO Auto-generated method stub
}
@Override
public void resultChanged(Result current) {
if (current instanceof SelectionResult || current instanceof Database) {
updateFromSelection();
dotTableModel.fireTableStructureChanged();
}
}
} SimpleSVGViewer.java 0000664 0000000 0000000 00000007650 12657057427 0034447 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/gui package de.lmu.ifi.dbs.elki.visualization.gui;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.HeadlessException;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.UIManager;
import de.lmu.ifi.dbs.elki.logging.LoggingUtil;
import de.lmu.ifi.dbs.elki.visualization.batikutil.JSVGSynchronizedCanvas;
import de.lmu.ifi.dbs.elki.visualization.savedialog.SVGSaveDialog;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGPlot;
/**
* A minimalistic SVG viewer with export dialog.
*
* @author Erich Schubert
* @since 0.4.0
*/
public class SimpleSVGViewer extends JFrame {
/**
* Serial version
*/
private static final long serialVersionUID = 1L;
/**
* The main canvas.
*/
private JSVGSynchronizedCanvas svgCanvas;
/**
* Constructor.
*
* @throws HeadlessException
*/
public SimpleSVGViewer() throws HeadlessException {
super();
// Prefer system look&feel
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch(Exception e) {
// ignore
}
// close handler
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// Maximize.
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
setSize(dim.width - 50, dim.height - 50);
// setup buttons
JMenuItem exportItem = new JMenuItem("Export");
exportItem.setMnemonic(KeyEvent.VK_E);
exportItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
saveCurrentPlot();
}
});
JMenuItem quitItem = new JMenuItem("Quit");
quitItem.setMnemonic(KeyEvent.VK_Q);
quitItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
close();
}
});
// Create a panel and add the button, status label and the SVG canvas.
final JPanel panel = new JPanel(new BorderLayout());
JMenuBar menubar = new JMenuBar();
menubar.add(exportItem);
menubar.add(quitItem);
panel.add("North", menubar);
svgCanvas = new JSVGSynchronizedCanvas();
panel.add("Center", svgCanvas);
this.getContentPane().add(panel);
setExtendedState(JFrame.MAXIMIZED_BOTH);
this.setVisible(true);
}
/**
* Close the visualizer window.
*/
public void close() {
this.setVisible(false);
this.dispose();
}
/**
* Save/export the current plot.
*/
public void saveCurrentPlot() {
// TODO: exclude "do not export" layers!
final SVGPlot currentPlot = svgCanvas.getPlot();
if(currentPlot != null) {
SVGSaveDialog.showSaveDialog(currentPlot, 512, 512);
}
else {
LoggingUtil.warning("saveCurrentPlot() called without a visible plot!");
}
}
/**
* Set the plot to show
*
* @param plot Plot
*/
public void setPlot(SVGPlot plot) {
svgCanvas.setPlot(plot);
}
} VisualizationPlot.java 0000664 0000000 0000000 00000004466 12657057427 0035156 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/gui package de.lmu.ifi.dbs.elki.visualization.gui;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.concurrent.ConcurrentLinkedDeque;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGPlot;
import de.lmu.ifi.dbs.elki.visualization.visualizers.Visualization;
/**
* SVG plot that allows visualization to schedule updates.
*
* @author Erich Schubert
* @since 0.7.0
*/
public class VisualizationPlot extends SVGPlot {
/**
* Pending redraw request in Batik.
*/
protected Runnable pendingRedraw = null;
/**
* Update queue.
*/
protected ConcurrentLinkedDeque updateQueue = new ConcurrentLinkedDeque<>();
/**
* Trigger a redraw, but avoid excessive redraws.
*/
protected final void synchronizedRedraw() {
Runnable pr = new Runnable() {
@Override
public void run() {
if(VisualizationPlot.this.pendingRedraw == this) {
VisualizationPlot.this.pendingRedraw = null;
VisualizationPlot.this.redraw();
}
}
};
pendingRedraw = pr;
scheduleUpdate(pr);
}
/**
* Redraw all pending updates.
*/
protected void redraw() {
while(!updateQueue.isEmpty()) {
Visualization vis = updateQueue.pop();
vis.incrementalRedraw();
}
}
/**
* Request a redraw of a visualization.
*/
public void requestRedraw(VisualizationTask task, Visualization vis) {
updateQueue.add(vis);
synchronizedRedraw();
}
}
elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/gui/detail/ 0000775 0000000 0000000 00000000000 12657057427 0032122 5 ustar 00root root 0000000 0000000 DetailView.java 0000664 0000000 0000000 00000027771 12657057427 0034761 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/gui/detail package de.lmu.ifi.dbs.elki.visualization.gui.detail;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.result.Result;
import de.lmu.ifi.dbs.elki.result.ResultListener;
import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.Hierarchy;
import de.lmu.ifi.dbs.elki.visualization.VisualizationItem;
import de.lmu.ifi.dbs.elki.visualization.VisualizationListener;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.css.CSSClass;
import de.lmu.ifi.dbs.elki.visualization.gui.VisualizationPlot;
import de.lmu.ifi.dbs.elki.visualization.gui.overview.PlotItem;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGEffects;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
import de.lmu.ifi.dbs.elki.visualization.visualizers.Visualization;
/**
* Manages a detail view.
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.has Visualization
* @apiviz.has PlotItem
* @apiviz.uses VisualizerContext
* @apiviz.uses VisualizationTask
*/
public class DetailView extends VisualizationPlot implements ResultListener, VisualizationListener {
/**
* Class logger
*/
private static final Logging LOG = Logging.getLogger(DetailView.class);
/**
* Meta information on the visualizers contained.
*/
private PlotItem item;
/**
* Ratio of this view.
*/
double ratio = 1.0;
/**
* The visualizer context
*/
VisualizerContext context;
/**
* Map from tasks to visualizations.
*/
Map taskmap = new HashMap<>();
/**
* Map from visualizations to SVG layers.
*/
Map layermap = new HashMap<>();
/**
* The created width
*/
private double width;
/**
* The created height
*/
private double height;
/**
* Pending refresh, for lazy refreshing
*/
AtomicReference pendingRefresh = new AtomicReference<>(null);
/**
* Constructor.
*
* @param vis Visualizations to use
* @param ratio Plot ratio
*/
public DetailView(VisualizerContext context, PlotItem vis, double ratio) {
super();
this.context = context;
this.item = new PlotItem(vis); // Clone!
this.ratio = ratio;
this.item.sort();
// TODO: only do this when there is an interactive visualizer?
setDisableInteractions(true);
addBackground(context);
SVGEffects.addShadowFilter(this);
SVGEffects.addLightGradient(this);
initialize();
context.addVisualizationListener(this);
context.addResultListener(this);
// FIXME: add datastore listener, too?
}
/**
* Create a background node. Note: don't call this at arbitrary times - the
* background may cover already drawn parts of the image!
*
* @param context
*/
private void addBackground(VisualizerContext context) {
// Make a background
CSSClass cls = new CSSClass(this, "background");
cls.setStatement(SVGConstants.CSS_FILL_PROPERTY, context.getStyleLibrary().getBackgroundColor(StyleLibrary.PAGE));
Element bg = this.svgElement(SVGConstants.SVG_RECT_TAG);
SVGUtil.setAtt(bg, SVGConstants.SVG_X_ATTRIBUTE, "0");
SVGUtil.setAtt(bg, SVGConstants.SVG_Y_ATTRIBUTE, "0");
SVGUtil.setAtt(bg, SVGConstants.SVG_WIDTH_ATTRIBUTE, "100%");
SVGUtil.setAtt(bg, SVGConstants.SVG_HEIGHT_ATTRIBUTE, "100%");
SVGUtil.setAtt(bg, NO_EXPORT_ATTRIBUTE, NO_EXPORT_ATTRIBUTE);
addCSSClassOrLogError(cls);
SVGUtil.setCSSClass(bg, cls.getName());
// Note that we rely on this being called before any other drawing routines.
getRoot().appendChild(bg);
}
private void initialize() {
// Try to keep the area approximately 1.0
width = Math.sqrt(getRatio());
height = 1.0 / width;
ArrayList layers = new ArrayList<>();
// TODO: center/arrange visualizations?
for(Iterator tit = item.tasks.iterator(); tit.hasNext();) {
VisualizationTask task = tit.next();
if(task.visible) {
Visualization v = instantiateVisualization(task);
if(v != null) {
layers.add(v);
taskmap.put(task, v);
layermap.put(v, v.getLayer());
}
}
}
// Arrange
for(Visualization layer : layers) {
if(layer.getLayer() != null) {
getRoot().appendChild(layer.getLayer());
}
else {
LOG.warning("NULL layer seen.");
}
}
double ratio = width / height;
getRoot().setAttribute(SVGConstants.SVG_WIDTH_ATTRIBUTE, "20cm");
getRoot().setAttribute(SVGConstants.SVG_HEIGHT_ATTRIBUTE, (20 / ratio) + "cm");
getRoot().setAttribute(SVGConstants.SVG_VIEW_BOX_ATTRIBUTE, "0 0 " + width + " " + height);
updateStyleElement();
}
/**
* Do a refresh (when visibilities have changed).
*/
private synchronized void refresh() {
pendingRefresh.set(null); // Clear
if(LOG.isDebuggingFine()) {
LOG.debugFine("Refresh in thread " + Thread.currentThread().getName());
}
boolean updateStyle = false;
Iterator> it = taskmap.entrySet().iterator();
while(it.hasNext()) {
Entry ent = it.next();
VisualizationTask task = ent.getKey();
Visualization vis = ent.getValue();
if(vis == null) {
vis = instantiateVisualization(task);
ent.setValue(vis);
}
Element prevlayer = layermap.get(vis);
Element layer = vis.getLayer();
if(prevlayer == layer) { // Unchanged:
// Current visibility ("not hidden")
boolean isVisible = !SVGConstants.CSS_HIDDEN_VALUE.equals(layer.getAttribute(SVGConstants.CSS_VISIBILITY_PROPERTY));
if(task.visible != isVisible) {
// scheduleUpdate(new AttributeModifier(
layer.setAttribute(SVGConstants.CSS_VISIBILITY_PROPERTY, //
task.visible ? SVGConstants.CSS_VISIBLE_VALUE : SVGConstants.CSS_HIDDEN_VALUE);
}
}
else {
if(task.hasAnyFlags(VisualizationTask.FLAG_NO_EXPORT)) {
layer.setAttribute(NO_EXPORT_ATTRIBUTE, NO_EXPORT_ATTRIBUTE);
}
if(prevlayer == null) {
if(LOG.isDebuggingFine()) {
LOG.debugFine("New layer: " + task);
}
// Insert new!
// TODO: insert position!
getRoot().appendChild(layer);
}
else {
if(LOG.isDebuggingFine()) {
LOG.debugFine("Updated layer: " + task);
}
// Replace
final Node parent = prevlayer.getParentNode();
if(parent != null) {
parent.replaceChild(/* new! */layer, /* old */prevlayer);
}
}
layermap.put(vis, layer);
updateStyle = true;
}
}
if(updateStyle) {
updateStyleElement();
}
}
/**
* Instantiate a visualization.
*
* @param task Task to instantiate
* @return Visualization
*/
private Visualization instantiateVisualization(VisualizationTask task) {
try {
Visualization v = task.getFactory().makeVisualization(task, this, width, height, item.proj);
if(task.hasAnyFlags(VisualizationTask.FLAG_NO_EXPORT)) {
v.getLayer().setAttribute(NO_EXPORT_ATTRIBUTE, NO_EXPORT_ATTRIBUTE);
}
return v;
}
catch(Exception e) {
if(LOG.isDebugging()) {
LOG.warning("Visualizer " + task.getFactory().getClass().getName() + " failed.", e);
}
else {
LOG.warning("Visualizer " + task.getFactory().getClass().getName() + " failed - enable debugging to see details: " + e.toString());
}
}
return null;
}
/**
* Cleanup function. To remove listeners.
*/
public void destroy() {
context.removeVisualizationListener(this);
context.removeResultListener(this);
for(Entry v : taskmap.entrySet()) {
Visualization vis = v.getValue();
if(vis != null) {
vis.destroy();
}
}
taskmap.clear();
}
@Override
public void dispose() {
destroy();
super.dispose();
}
/**
* Get the plot ratio.
*
* @return the current ratio
*/
public double getRatio() {
return ratio;
}
/**
* Set the plot ratio
*
* @param ratio the new ratio to set
*/
public void setRatio(double ratio) {
// TODO: trigger refresh?
this.ratio = ratio;
}
/**
* Trigger a refresh.
*/
private void lazyRefresh() {
Runnable pr = new Runnable() {
@Override
public void run() {
if(DetailView.this.pendingRefresh.compareAndSet(this, null)) {
DetailView.this.refresh();
}
}
};
DetailView.this.pendingRefresh.set(pr);
scheduleUpdate(pr);
}
@Override
public void resultAdded(Result child, Result parent) {
lazyRefresh();
}
@Override
public void resultChanged(Result current) {
lazyRefresh();
}
@Override
public void resultRemoved(Result child, Result parent) {
lazyRefresh();
}
@Override
public void visualizationChanged(VisualizationItem current) {
// Make sure we are affected:
if(!(current instanceof VisualizationTask)) {
return;
}
final VisualizationTask task = (VisualizationTask) current;
// Get the layer
Visualization vis = taskmap.get(task);
if(vis == null) { // Unknown only.
boolean include = false;
Hierarchy.Iter it = context.getVisHierarchy().iterAncestors(current);
for(; it.valid(); it.advance()) {
if((item.proj != null && item.proj.getProjector() == it.get()) || taskmap.containsKey(it.get())) {
include = true;
break;
}
}
if(!include) {
return; // Attached to different projection.
}
}
if(vis == null) { // New visualization
taskmap.put(task, null);
lazyRefresh();
}
else {
Element prevlayer = layermap.get(vis);
Element layer = vis.getLayer();
if(prevlayer != layer) {
lazyRefresh();
}
else {
boolean isVisible = !SVGConstants.CSS_HIDDEN_VALUE.equals(layer.getAttribute(SVGConstants.CSS_VISIBILITY_PROPERTY));
if(task.visible != isVisible) {
lazyRefresh(); // Visibility has changed.
}
}
}
}
@Override
protected void redraw() {
boolean active = false;
while(!updateQueue.isEmpty()) {
Visualization vis = updateQueue.pop();
if(!active) {
Element prev = layermap.get(vis);
vis.incrementalRedraw();
final boolean changed = prev != vis.getLayer();
if(LOG.isDebuggingFine() && changed) {
LOG.debugFine("Visualization " + vis + " changed.");
}
active |= changed;
}
else {
vis.incrementalRedraw();
}
}
if(active || true) {
refresh();
}
}
/**
* Get the item visualized by this view.
*
* @return Plot item
*/
public PlotItem getPlotItem() {
return item;
}
}
package-info.java 0000775 0000000 0000000 00000001731 12657057427 0035237 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/gui/detail /**
*
Classes for managing a detail view.
*
*/
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.lmu.ifi.dbs.elki.visualization.gui.detail; elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/gui/overview/ 0000775 0000000 0000000 00000000000 12657057427 0032526 5 ustar 00root root 0000000 0000000 DetailViewSelectedEvent.java 0000664 0000000 0000000 00000004060 12657057427 0040022 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/gui/overview package de.lmu.ifi.dbs.elki.visualization.gui.overview;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.awt.event.ActionEvent;
import de.lmu.ifi.dbs.elki.visualization.gui.detail.DetailView;
/**
* Event when a particular subplot was selected. Plots are currently identified
* by their coordinates on the screen.
*
* @author Erich Schubert
* @since 0.3
*/
public class DetailViewSelectedEvent extends ActionEvent {
/**
* Serial version
*/
private static final long serialVersionUID = 1L;
/**
* Parent overview plot.
*/
OverviewPlot overview;
/**
* Plot item selected
*/
PlotItem it;
/**
* Constructor. To be called by OverviewPlot only!
*
* @param source source plot
* @param id ID
* @param command command that was invoked
* @param modifiers modifiers
* @param it Plot item selected
*/
public DetailViewSelectedEvent(OverviewPlot source, int id, String command, int modifiers, PlotItem it) {
super(source, id, command, modifiers);
this.overview = source;
this.it = it;
}
/**
* Retrieve a materialized detail plot.
*
* @return materialized detail plot
*/
public DetailView makeDetailView() {
return overview.makeDetailView(it);
}
} LayerMap.java 0000664 0000000 0000000 00000010244 12657057427 0035025 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/gui/overview package de.lmu.ifi.dbs.elki.visualization.gui.overview;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.*;
import org.w3c.dom.Element;
import de.lmu.ifi.dbs.elki.utilities.pairs.Pair;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.visualizers.Visualization;
/**
* Class to help keeping track of the materialized layers of the different visualizations.
*
* @author Erich Schubert
* @since 0.5.0
*
* @apiviz.has PlotItem
* @apiviz.has VisualizationTask
*/
public class LayerMap {
/**
* The actual map
*/
private HashMap, Pair> map = new HashMap<>();
/**
* Helper function for building a key object
*
* @param item Plot item
* @param task Visualization Task
* @return Key
*/
private Pair key(PlotItem item, VisualizationTask task) {
return new Pair<>(item, task);
}
/**
* Helper function to build a value pair
*
* @param elem Container element
* @param vis Visualization
* @return Value object
*/
private Pair value(Element elem, Visualization vis) {
return new Pair<>(elem, vis);
}
/**
* Get the visualization referenced by a item/key combination.
*
* @param item Plot ttem
* @param task Visualization task
* @return Visualization
*/
public Visualization getVisualization(PlotItem item, VisualizationTask task) {
Pair pair = map.get(key(item, task));
if (pair == null) {
return null;
} else {
return pair.second;
}
}
/**
* Get the container element referenced by a item/key combination.
*
* @param item Plot item
* @param task Visualization task
* @return Container element
*/
public Element getContainer(PlotItem item, VisualizationTask task) {
Pair pair = map.get(key(item, task));
if (pair == null) {
return null;
} else {
return pair.first;
}
}
/**
* Iterate over values
*
* @return Value iterable
*/
public Iterable> values() {
return map.values();
}
/**
* Clear a map
*/
public void clear() {
map.clear();
}
/**
* Put a new combination into the map.
*
* @param it Plot item
* @param task Visualization Task
* @param elem Container element
* @param vis Visualization
*/
public void put(PlotItem it, VisualizationTask task, Element elem, Visualization vis) {
map.put(key(it, task), value(elem, vis));
}
/**
* Remove a combination.
*
* @param it Plot item
* @param task Visualization task
* @return Previous value
*/
public Pair remove(PlotItem it, VisualizationTask task) {
return map.remove(key(it, task));
}
/**
* Put a new item into the visualizations
*
* @param it Plot item
* @param task Visualization task
* @param pair Pair object
*/
public void put(PlotItem it, VisualizationTask task, Pair pair) {
map.put(key(it, task), pair);
}
/**
* Get a pair from the map
*
* @param it Plot item
* @param task Visualization task
* @return Pair object
*/
public Pair get(PlotItem it, VisualizationTask task) {
return map.get(key(it, task));
}
} OverviewPlot.java 0000664 0000000 0000000 00000047716 12657057427 0035776 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/gui/overview package de.lmu.ifi.dbs.elki.visualization.gui.overview;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventListener;
import org.w3c.dom.events.EventTarget;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.logging.LoggingUtil;
import de.lmu.ifi.dbs.elki.result.Result;
import de.lmu.ifi.dbs.elki.result.ResultListener;
import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.Hierarchy;
import de.lmu.ifi.dbs.elki.utilities.pairs.Pair;
import de.lmu.ifi.dbs.elki.visualization.VisualizationItem;
import de.lmu.ifi.dbs.elki.visualization.VisualizationListener;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.batikutil.CSSHoverClass;
import de.lmu.ifi.dbs.elki.visualization.css.CSSClass;
import de.lmu.ifi.dbs.elki.visualization.gui.VisualizationPlot;
import de.lmu.ifi.dbs.elki.visualization.gui.detail.DetailView;
import de.lmu.ifi.dbs.elki.visualization.projector.Projector;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGEffects;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGPlot;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
import de.lmu.ifi.dbs.elki.visualization.visualizers.Visualization;
/**
* Generate an overview plot for a set of visualizations.
*
* @author Erich Schubert
* @author Remigius Wojdanowski
* @since 0.3
*
* @apiviz.landmark
* @apiviz.has VisualizerContext
* @apiviz.composedOf RectangleArranger
* @apiviz.composedOf LayerMap
* @apiviz.has DetailViewSelectedEvent
* @apiviz.uses DetailView
*/
public class OverviewPlot implements ResultListener, VisualizationListener {
/**
* Our logging class
*/
private static final Logging LOG = Logging.getLogger(OverviewPlot.class);
/**
* Event when the overview plot started refreshing.
*/
public static final String OVERVIEW_REFRESHING = "Overview refreshing";
/**
* Event when the overview plot was refreshed.
*/
public static final String OVERVIEW_REFRESHED = "Overview refreshed";
/**
* Draw red borders around items.
*/
private static final boolean DEBUG_LAYOUT = false;
/**
* Visualizer context
*/
private VisualizerContext context;
/**
* The SVG plot object.
*/
private VisualizationPlot plot;
/**
* Map of coordinates to plots.
*/
protected RectangleArranger plotmap;
/**
* Action listeners for this plot.
*/
private ArrayList actionListeners = new ArrayList<>();
/**
* Single view mode
*/
private boolean single;
/**
* Screen size (used for thumbnail sizing)
*/
public int screenwidth = 2000;
/**
* Screen size (used for thumbnail sizing)
*/
public int screenheight = 2000;
/**
* React to mouse hover events
*/
private EventListener hoverer;
/**
* Lookup
*/
private LayerMap vistoelem = new LayerMap();
/**
* Layer for plot thumbnail
*/
private Element plotlayer;
/**
* Layer for hover elements
*/
private Element hoverlayer;
/**
* The CSS class used on "selectable" rectangles.
*/
private CSSClass selcss;
/**
* Screen ratio
*/
private double ratio = 1.0;
/**
* Pending refresh, for lazy refreshing
*/
AtomicReference pendingRefresh = new AtomicReference<>(null);
/**
* Reinitialize on refresh
*/
private boolean reinitOnRefresh = false;
/**
* Constructor.
*
* @param context Visualizer context
* @param single Single view mode
*/
public OverviewPlot(VisualizerContext context, boolean single) {
super();
this.context = context;
this.single = single;
// Important:
// You still need to call: initialize(ratio);
}
/**
* Recompute the layout of visualizations.
*
* @param width Initial width
* @param height Initial height
* @return Arrangement
*/
private RectangleArranger arrangeVisualizations(double width, double height) {
if(!(width > 0. && height > 0.)) {
LOG.warning("No size information during arrange()", new Throwable());
return new RectangleArranger<>(1., 1.);
}
RectangleArranger plotmap = new RectangleArranger<>(width, height);
Hierarchy vistree = context.getVisHierarchy();
for(Hierarchy.Iter> iter2 = vistree.iterAll(); iter2.valid(); iter2.advance()) {
if(!(iter2.get() instanceof Projector)) {
continue;
}
Projector p = (Projector) iter2.get();
Collection projs = p.arrange(context);
for(PlotItem it : projs) {
if(it.w <= 0.0 || it.h <= 0.0) {
LOG.warning("Plot item with improper size information: " + it);
continue;
}
plotmap.put(it.w, it.h, it);
}
}
nextTask: for(Hierarchy.Iter> iter2 = vistree.iterAll(); iter2.valid(); iter2.advance()) {
if(!(iter2.get() instanceof VisualizationTask)) {
continue;
}
VisualizationTask task = (VisualizationTask) iter2.get();
if(!task.visible) {
continue;
}
for(Hierarchy.Iter> iter = vistree.iterParents(task); iter.valid(); iter.advance()) {
if(iter.get() instanceof Projector) {
continue nextTask;
}
}
if(task.reqwidth <= 0.0 || task.reqheight <= 0.0) {
LOG.warning("Task with improper size information: " + task);
continue;
}
PlotItem it = new PlotItem(task.reqwidth, task.reqheight, null);
it.tasks.add(task);
plotmap.put(it.w, it.h, it);
}
return plotmap;
}
/**
* Initialize the plot.
*
* @param ratio Initial ratio
*/
public void initialize(double ratio) {
if(!(ratio > 0 && ratio < Double.POSITIVE_INFINITY)) {
LOG.warning("Invalid ratio: " + ratio, new Throwable());
ratio = 1.4;
}
this.ratio = ratio;
if(plot != null) {
LOG.warning("Already initialized.");
lazyRefresh();
return;
}
reinitialize();
// register context listener
context.addResultListener(this);
context.addVisualizationListener(this);
}
/**
* Refresh the overview plot.
*/
private synchronized void reinitialize() {
if(plot == null) {
initializePlot();
}
else {
final ActionEvent ev = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, OVERVIEW_REFRESHING);
for(ActionListener actionListener : actionListeners) {
actionListener.actionPerformed(ev);
}
}
// Detach existing elements:
for(Pair pair : vistoelem.values()) {
SVGUtil.removeFromParent(pair.first);
}
plotmap = arrangeVisualizations(ratio, 1.0);
recalcViewbox();
final int thumbsize = (int) Math.max(screenwidth / plotmap.getWidth(), screenheight / plotmap.getHeight());
// TODO: cancel pending thumbnail requests!
// Replace the layer map
LayerMap oldlayers = vistoelem;
vistoelem = new LayerMap();
// Redo main layers
SVGUtil.removeFromParent(plotlayer);
SVGUtil.removeFromParent(hoverlayer);
plotlayer = plot.svgElement(SVGConstants.SVG_G_TAG);
hoverlayer = plot.svgElement(SVGConstants.SVG_G_TAG);
hoverlayer.setAttribute(SVGPlot.NO_EXPORT_ATTRIBUTE, SVGPlot.NO_EXPORT_ATTRIBUTE);
// Redo the layout
for(Entry e : plotmap.entrySet()) {
final double basex = e.getValue()[0];
final double basey = e.getValue()[1];
for(Iterator iter = e.getKey().itemIterator(); iter.hasNext();) {
PlotItem it = iter.next();
boolean hasDetails = false;
// Container element for main plot item
Element g = plot.svgElement(SVGConstants.SVG_G_TAG);
SVGUtil.setAtt(g, SVGConstants.SVG_TRANSFORM_ATTRIBUTE, "translate(" + (basex + it.x) + " " + (basey + it.y) + ")");
plotlayer.appendChild(g);
vistoelem.put(it, null, g, null);
// Add the actual tasks:
for(VisualizationTask task : it.tasks) {
if(!visibleInOverview(task)) {
continue;
}
hasDetails |= !task.hasAnyFlags(VisualizationTask.FLAG_NO_DETAIL);
Pair pair = oldlayers.remove(it, task);
if(pair == null) {
pair = new Pair<>(null, null);
pair.first = plot.svgElement(SVGConstants.SVG_G_TAG);
}
if(pair.second == null) {
pair.second = embedOrThumbnail(thumbsize, it, task, pair.first);
}
g.appendChild(pair.first);
vistoelem.put(it, task, pair);
}
// When needed, add a hover effect
if(hasDetails && !single) {
Element hover = plot.svgRect(basex + it.x, basey + it.y, it.w, it.h);
SVGUtil.addCSSClass(hover, selcss.getName());
// link hoverer.
EventTarget targ = (EventTarget) hover;
targ.addEventListener(SVGConstants.SVG_MOUSEOVER_EVENT_TYPE, hoverer, false);
targ.addEventListener(SVGConstants.SVG_MOUSEOUT_EVENT_TYPE, hoverer, false);
targ.addEventListener(SVGConstants.SVG_CLICK_EVENT_TYPE, hoverer, false);
targ.addEventListener(SVGConstants.SVG_CLICK_EVENT_TYPE, new SelectPlotEvent(it), false);
hoverlayer.appendChild(hover);
}
}
}
for(Pair pair : oldlayers.values()) {
if(pair.second != null) {
pair.second.destroy();
}
}
plot.getRoot().appendChild(plotlayer);
plot.getRoot().appendChild(hoverlayer);
plot.updateStyleElement();
// Notify listeners.
final ActionEvent ev = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, OVERVIEW_REFRESHED);
for(ActionListener actionListener : actionListeners) {
actionListener.actionPerformed(ev);
}
}
/**
* Initialize the SVG plot.
*/
private void initializePlot() {
plot = new VisualizationPlot();
{ // Add a background element:
CSSClass cls = new CSSClass(this, "background");
final String bgcol = context.getStyleLibrary().getBackgroundColor(StyleLibrary.PAGE);
cls.setStatement(SVGConstants.CSS_FILL_PROPERTY, bgcol);
plot.addCSSClassOrLogError(cls);
Element background = plot.svgElement(SVGConstants.SVG_RECT_TAG);
background.setAttribute(SVGConstants.SVG_X_ATTRIBUTE, "0");
background.setAttribute(SVGConstants.SVG_Y_ATTRIBUTE, "0");
background.setAttribute(SVGConstants.SVG_WIDTH_ATTRIBUTE, "100%");
background.setAttribute(SVGConstants.SVG_HEIGHT_ATTRIBUTE, "100%");
SVGUtil.setCSSClass(background, cls.getName());
// Don't export a white background:
if("white".equals(bgcol)) {
background.setAttribute(SVGPlot.NO_EXPORT_ATTRIBUTE, SVGPlot.NO_EXPORT_ATTRIBUTE);
}
plot.getRoot().appendChild(background);
}
{ // setup the hover CSS classes.
selcss = new CSSClass(this, "s");
if(DEBUG_LAYOUT) {
selcss.setStatement(SVGConstants.CSS_STROKE_PROPERTY, SVGConstants.CSS_RED_VALUE);
selcss.setStatement(SVGConstants.CSS_STROKE_WIDTH_PROPERTY, .00001 * StyleLibrary.SCALE);
selcss.setStatement(SVGConstants.CSS_STROKE_OPACITY_PROPERTY, "0.5");
}
selcss.setStatement(SVGConstants.CSS_FILL_PROPERTY, SVGConstants.CSS_RED_VALUE);
selcss.setStatement(SVGConstants.CSS_FILL_OPACITY_PROPERTY, "0");
selcss.setStatement(SVGConstants.CSS_CURSOR_PROPERTY, SVGConstants.CSS_POINTER_VALUE);
plot.addCSSClassOrLogError(selcss);
CSSClass hovcss = new CSSClass(this, "h");
hovcss.setStatement(SVGConstants.CSS_FILL_OPACITY_PROPERTY, "0.25");
plot.addCSSClassOrLogError(hovcss);
// Hover listener.
hoverer = new CSSHoverClass(hovcss.getName(), null, true);
}
// Disable Batik default interactions (zoom, rotate, etc.)
if(single) {
plot.setDisableInteractions(true);
}
SVGEffects.addShadowFilter(plot);
SVGEffects.addLightGradient(plot);
}
/**
* Produce thumbnail for a visualizer.
*
* @param thumbsize Thumbnail size
* @param it Plot item
* @param task Task
* @param parent Parent element to draw to
*/
private Visualization embedOrThumbnail(final int thumbsize, PlotItem it, VisualizationTask task, Element parent) {
final Visualization vis;
if(!single) {
vis = task.getFactory().makeVisualizationOrThumbnail(task, plot, it.w, it.h, it.proj, thumbsize);
}
else {
vis = task.getFactory().makeVisualization(task, plot, it.w, it.h, it.proj);
}
if(vis == null || vis.getLayer() == null) {
LoggingUtil.warning("Visualization returned empty layer: " + vis);
return vis;
}
if(task.hasAnyFlags(VisualizationTask.FLAG_NO_EXPORT)) {
vis.getLayer().setAttribute(SVGPlot.NO_EXPORT_ATTRIBUTE, SVGPlot.NO_EXPORT_ATTRIBUTE);
}
parent.appendChild(vis.getLayer());
return vis;
}
/**
* Do a refresh (when visibilities have changed).
*/
synchronized void refresh() {
if(reinitOnRefresh) {
LOG.debug("Reinitialize in thread " + Thread.currentThread().getName());
reinitialize();
reinitOnRefresh = false;
return;
}
synchronized(plot) {
boolean refreshcss = false;
if(plotmap == null) {
LOG.warning("Plotmap is null", new Throwable());
}
final int thumbsize = (int) Math.max(screenwidth / plotmap.getWidth(), screenheight / plotmap.getHeight());
for(PlotItem pi : plotmap.keySet()) {
for(Iterator iter = pi.itemIterator(); iter.hasNext();) {
PlotItem it = iter.next();
for(Iterator tit = it.tasks.iterator(); tit.hasNext();) {
VisualizationTask task = tit.next();
Pair pair = vistoelem.get(it, task);
// New task?
if(pair == null) {
if(visibleInOverview(task)) {
pair = new Pair<>(null, null);
pair.first = plot.svgElement(SVGConstants.SVG_G_TAG);
pair.second = embedOrThumbnail(thumbsize, it, task, pair.first);
vistoelem.get(it, null).first.appendChild(pair.first);
vistoelem.put(it, task, pair);
refreshcss = true;
}
}
else {
if(visibleInOverview(task)) {
// unhide if hidden.
if(pair.first.hasAttribute(SVGConstants.CSS_VISIBILITY_PROPERTY)) {
pair.first.removeAttribute(SVGConstants.CSS_VISIBILITY_PROPERTY);
}
}
else {
// hide if there is anything to hide.
if(pair.first != null && pair.first.hasChildNodes()) {
pair.first.setAttribute(SVGConstants.CSS_VISIBILITY_PROPERTY, SVGConstants.CSS_HIDDEN_VALUE);
}
}
// TODO: unqueue pending thumbnails
}
}
}
}
if(refreshcss) {
plot.updateStyleElement();
}
}
}
/**
* Test whether a task should be displayed in the overview plot.
*
* @param task Task to display
* @return visibility
*/
protected boolean visibleInOverview(VisualizationTask task) {
if(single) {
return task.visible && !task.hasAnyFlags(VisualizationTask.FLAG_NO_EMBED);
}
return task.visible && !task.hasAnyFlags(VisualizationTask.FLAG_NO_THUMBNAIL);
}
/**
* Recompute the view box of the plot.
*/
private void recalcViewbox() {
final Element root = plot.getRoot();
// Reset plot attributes
SVGUtil.setAtt(root, SVGConstants.SVG_WIDTH_ATTRIBUTE, "20cm");
SVGUtil.setAtt(root, SVGConstants.SVG_HEIGHT_ATTRIBUTE, SVGUtil.fmt(20 * plotmap.getHeight() / plotmap.getWidth()) + "cm");
String vb = "0 0 " + SVGUtil.fmt(plotmap.getWidth()) + " " + SVGUtil.fmt(plotmap.getHeight());
SVGUtil.setAtt(root, SVGConstants.SVG_VIEW_BOX_ATTRIBUTE, vb);
}
/**
* Event triggered when a plot was selected.
*
* @param it Plot item selected
* @return sub plot
*/
public DetailView makeDetailView(PlotItem it) {
return new DetailView(context, it, ratio);
}
/**
* Adds an {@link ActionListener} to the plot.
*
* @param actionListener the {@link ActionListener} to be added
*/
public void addActionListener(ActionListener actionListener) {
actionListeners.add(actionListener);
}
/**
* When a subplot was selected, forward the event to listeners.
*
* @param it PlotItem selected
*/
protected void triggerSubplotSelectEvent(PlotItem it) {
// forward event to all listeners.
for(ActionListener actionListener : actionListeners) {
actionListener.actionPerformed(new DetailViewSelectedEvent(this, ActionEvent.ACTION_PERFORMED, null, 0, it));
}
}
/**
* Event when a plot was selected.
*
* @author Erich Schubert
*
* @apiviz.exclude
*/
public class SelectPlotEvent implements EventListener {
/**
* Plot item clicked
*/
PlotItem it;
/**
* Constructor.
*
* @param it Item that was clicked
*/
public SelectPlotEvent(PlotItem it) {
super();
this.it = it;
}
@Override
public void handleEvent(Event evt) {
triggerSubplotSelectEvent(it);
}
}
/**
* Destroy this overview plot.
*/
public void destroy() {
context.removeVisualizationListener(this);
context.removeResultListener(this);
plot.dispose();
}
/**
* Get the SVGPlot object.
*
* @return SVG plot
*/
public SVGPlot getPlot() {
return plot;
}
/**
* @return the ratio
*/
public double getRatio() {
return ratio;
}
/**
* @param ratio the ratio to set
*/
public void setRatio(double ratio) {
if(ratio != this.ratio) {
this.ratio = ratio;
reinitOnRefresh = true;
lazyRefresh();
}
}
/**
* Trigger a redraw, but avoid excessive redraws.
*/
public final void lazyRefresh() {
if(plot == null) {
LOG.warning("'lazyRefresh' called before initialized!");
}
LOG.debug("Scheduling refresh.");
Runnable pr = new Runnable() {
@Override
public void run() {
if(OverviewPlot.this.pendingRefresh.compareAndSet(this, null)) {
OverviewPlot.this.refresh();
}
}
};
OverviewPlot.this.pendingRefresh.set(pr);
plot.scheduleUpdate(pr);
}
@Override
public void resultAdded(Result child, Result parent) {
lazyRefresh();
}
@Override
public void resultChanged(Result current) {
lazyRefresh();
}
@Override
public void resultRemoved(Result child, Result parent) {
lazyRefresh();
}
@Override
public void visualizationChanged(VisualizationItem child) {
boolean isProjected = false;
for(Hierarchy.Iter iter = context.getVisHierarchy().iterParents(child); iter.valid(); iter.advance()) {
final Object o = iter.get();
if(o instanceof Projector) {
isProjected = true;
break;
}
}
if(!isProjected) {
reinitOnRefresh = true;
}
lazyRefresh();
}
}
PlotItem.java 0000664 0000000 0000000 00000011322 12657057427 0035046 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/gui/overview package de.lmu.ifi.dbs.elki.visualization.gui.overview;
import java.util.ArrayList;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.projections.Projection;
/**
* Item to collect visualization tasks on a specific position on the plot map.
*
* Note: this is a {@code LinkedList}!
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.composedOf Projection
* @apiviz.composedOf VisualizationTask
* @apiviz.composedOf PlotItem
*/
public class PlotItem {
/**
* Position: x
*/
public final double x;
/**
* Position: y
*/
public final double y;
/**
* Size: width
*/
public final double w;
/**
* Size: height
*/
public final double h;
/**
* Projection (may be {@code null}!)
*/
public final Projection proj;
/**
* The visualization tasks at this location
*/
public List tasks = new LinkedList<>();
/**
* Subitems to plot
*/
public Collection subitems = new LinkedList<>();
/**
* Constructor.
*
* @param w Position: w
* @param h Position: h
* @param proj Projection
*/
public PlotItem(double w, double h, Projection proj) {
this(0, 0, w, h, proj);
}
/**
* Constructor.
*
* @param x Position: x
* @param y Position: y
* @param w Position: w
* @param h Position: h
* @param proj Projection
*/
public PlotItem(double x, double y, double w, double h, Projection proj) {
super();
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.proj = proj;
}
/**
* Clone constructor.
*
* @param vis Existing plot item.
*/
public PlotItem(PlotItem vis) {
super();
this.x = vis.x;
this.y = vis.y;
this.w = vis.w;
this.h = vis.h;
this.proj = vis.proj;
this.tasks = new ArrayList<>(vis.tasks);
this.subitems = new ArrayList<>(vis.subitems.size());
for(PlotItem s : vis.subitems) {
this.subitems.add(new PlotItem(s));
}
}
/**
* Sort all visualizers for their proper drawing order
*/
public void sort() {
Collections.sort(tasks);
for(PlotItem subitem : subitems) {
subitem.sort();
}
}
/**
* Add a task to the item.
*
* @param task Task to add
*/
public void add(VisualizationTask task) {
tasks.add(task);
}
/**
* Number of tasks in this item.
*
* @return Number of tasks.
*/
public int taskSize() {
return tasks.size();
}
/**
* Iterate (recursively) over all plot items, including itself.
*
* @return Iterator
*/
public Iterator itemIterator() {
return new ItmItr();
}
@Override
public String toString() {
return "PlotItem [x=" + x + ", y=" + y + ", w=" + w + ", h=" + h + ",proj=" + proj + "]";
}
/**
* Recursive iterator
*
* @author Erich Schubert
*
* @apiviz.exclude
*/
private class ItmItr implements Iterator {
PlotItem next;
Iterator cur;
Iterator sub;
/**
* Constructor.
*/
public ItmItr() {
super();
this.next = PlotItem.this;
this.cur = null;
this.sub = subitems.iterator();
}
@Override
public boolean hasNext() {
if(next != null) {
return true;
}
if(cur != null && cur.hasNext()) {
next = cur.next();
return true;
}
if(sub.hasNext()) {
cur = sub.next().itemIterator();
return hasNext();
}
return false;
}
@Override
public PlotItem next() {
hasNext();
PlotItem ret = next;
next = null;
return ret;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
} RectangleArranger.java 0000664 0000000 0000000 00000033353 12657057427 0036707 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/gui/overview package de.lmu.ifi.dbs.elki.visualization.gui.overview;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Level;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.logging.LoggingConfiguration;
import de.lmu.ifi.dbs.elki.utilities.datastructures.arraylike.DoubleArray;
/**
* This is a rather naive rectangle arrangement class. It will try to place
* rectangles on a canvas while maintaining the canvas size ratio as good as
* possible. It does not do an exhaustive search for optimizing the layout, but
* a greedy placement strategy, extending the canvas as little as possible.
*
* @author Erich Schubert
* @since 0.4.0
*
* @param Key type
*/
public class RectangleArranger {
/**
* Logging class
*/
private static final Logging LOG = Logging.getLogger(RectangleArranger.class);
/**
* Target height/width ratio
*/
private double ratio = 1.0;
/**
* Width
*/
private double twidth = 1.0;
/**
* Height
*/
private double theight = 1.0;
/**
* Column widths
*/
private DoubleArray widths = new DoubleArray();
/**
* Column heights
*/
private DoubleArray heights = new DoubleArray();
/**
* Map indicating which cells are used.
*/
private ArrayList> usage = new ArrayList<>();
/**
* Data
*/
private Map map = new HashMap<>();
/**
* Constructor.
*
* @param ratio
*/
public RectangleArranger(double ratio) {
this(ratio, 1.0);
}
/**
* Constructor.
*
* @param width Canvas width
* @param height Canvas height
*/
public RectangleArranger(double width, double height) {
this.ratio = width / height;
this.twidth = width;
this.theight = height;
this.widths.add(width);
this.heights.add(height);
// setup usage matrix
ArrayList u = new ArrayList<>();
u.add(null);
this.usage.add(u);
assertConsistent();
}
/**
* Add a new recangle.
*
* @param w Width
* @param h Height
* @param data Data object to add (key)
*/
public void put(double w, double h, T data) {
if(LOG.isDebuggingFinest()) {
LOG.finest("Add: " + w + "x" + h);
}
final int cols = widths.size();
final int rows = heights.size();
int bestsx = -1;
int bestsy = -1;
int bestex = cols - 1;
int bestey = -1;
double bestwi;
double besthi;
double bestinc;
// Baseline: grow by adding to the top or to the right.
{
double i1 = computeIncreaseArea(w, Math.max(0, h - theight));
double i2 = computeIncreaseArea(Math.max(0, w - twidth), h);
if(i1 < i2) {
bestwi = w;
besthi = Math.max(0, h - theight);
bestinc = i1;
}
else {
bestwi = Math.max(0, w - twidth);
besthi = h;
bestinc = i2;
}
}
// Find position with minimum increase
for(int sy = 0; sy < rows; sy++) {
for(int sx = 0; sx < cols; sx++) {
if(usage.get(sy).get(sx) != null) {
continue;
}
// Start with single cell
double avw = widths.get(sx);
double avh = heights.get(sy);
int ex = sx;
int ey = sy;
while(avw < w || avh < h) {
// Grow width first
if(avw / avh < w / h) {
if(avw < w && ex + 1 < cols) {
boolean ok = true;
// All unused?
for(int y = sy; y <= ey; y++) {
if(usage.get(y).get(ex + 1) != null) {
ok = false;
}
}
if(ok) {
ex += 1;
avw += widths.get(ex);
continue;
}
}
if(avh < h && ey + 1 < rows) {
boolean ok = true;
// All unused?
for(int x = sx; x <= ex; x++) {
if(usage.get(ey + 1).get(x) != null) {
ok = false;
}
}
if(ok) {
ey += 1;
avh += heights.get(ey);
continue;
}
}
}
else { // Grow height first
if(avh < h && ey + 1 < rows) {
boolean ok = true;
// All unused?
for(int x = sx; x <= ex; x++) {
if(usage.get(ey + 1).get(x) != null) {
ok = false;
}
}
if(ok) {
ey += 1;
avh += heights.get(ey);
continue;
}
}
if(avw < w && ex + 1 < cols) {
boolean ok = true;
// All unused?
for(int y = sy; y <= ey; y++) {
if(usage.get(y).get(ex + 1) != null) {
ok = false;
}
}
if(ok) {
ex += 1;
avw += widths.get(ex);
continue;
}
}
}
break;
}
// Good match, or extension possible?
if(avw < w && ex < cols - 1) {
continue;
}
if(avh < h && ey < rows - 1) {
continue;
}
// Compute increase:
double winc = Math.max(0.0, w - avw);
double hinc = Math.max(0.0, h - avh);
double inc = computeIncreaseArea(winc, hinc);
if(LOG.isDebuggingFinest()) {
LOG.debugFinest("Candidate: " + sx + "," + sy + " - " + ex + "," + ey + ": " + avw + "x" + avh + " " + inc);
}
if(inc < bestinc) {
bestinc = inc;
bestsx = sx;
bestsy = sy;
bestex = ex;
bestey = ey;
bestwi = w - avw;
besthi = h - avh;
}
if(inc == 0) {
// Can't find better
// TODO: try to do less splitting maybe?
break;
}
}
assert assertConsistent();
}
if(LOG.isDebuggingFinest()) {
LOG.debugFinest("Best: " + bestsx + "," + bestsy + " - " + bestex + "," + bestey + " inc: " + bestwi + "x" + besthi + " " + bestinc);
}
// Need to increase the total area
if(bestinc > 0) {
assert(bestex == cols - 1 || bestey == rows - 1);
double inc = Math.max(bestwi, besthi * ratio);
resize(inc);
// Resubmit
put(w, h, data);
return;
}
// Need to split a column.
// TODO: find best column to split. Currently: last
if(bestwi < 0.0) {
splitCol(bestex, -bestwi);
bestwi = 0.0;
}
// Need to split a row.
// TODO: find best row to split. Currently: last
if(besthi < 0.0) {
splitRow(bestey, -besthi);
besthi = 0.0;
}
for(int x = bestsx; x <= bestex; x++) {
for(int y = bestsy; y <= bestey; y++) {
usage.get(y).set(x, data);
}
}
double xpos = 0.0;
double ypos = 0.0;
{
for(int x = 0; x < bestsx; x++) {
xpos += widths.get(x);
}
for(int y = 0; y < bestsy; y++) {
ypos += heights.get(y);
}
}
map.put(data, new double[] { xpos, ypos, w, h });
if(LOG.isDebuggingFinest()) {
logSizes();
}
}
protected double computeIncreaseArea(double winc, double hinc) {
double inc = Math.max(winc, hinc * ratio);
inc = inc * (hinc + inc / ratio + winc / ratio);
return inc;
}
protected void splitRow(int bestey, double besthi) {
assert(bestey < heights.size());
if(heights.get(bestey) - besthi <= Double.MIN_NORMAL) {
return;
}
if(LOG.isDebuggingFine()) {
LOG.debugFine("Split row " + bestey);
}
heights.insert(bestey + 1, besthi);
heights.set(bestey, heights.get(bestey) - besthi);
// Update used map
usage.add(bestey + 1, new ArrayList<>(usage.get(bestey)));
}
protected void splitCol(int bestex, double bestwi) {
assert(bestex < widths.size());
if(widths.get(bestex) - bestwi <= Double.MIN_NORMAL) {
return;
}
final int rows = heights.size();
if(LOG.isDebuggingFine()) {
LOG.debugFine("Split column " + bestex);
}
widths.insert(bestex + 1, bestwi);
widths.set(bestex, widths.get(bestex) - bestwi);
// Update used map
for(int y = 0; y < rows; y++) {
usage.get(y).add(bestex + 1, usage.get(y).get(bestex));
}
assert assertConsistent();
}
private void resize(double inc) {
final int cols = widths.size();
final int rows = heights.size();
if(LOG.isDebuggingFine()) {
LOG.debugFine("Resize by " + inc + "x" + (inc / ratio));
if(LOG.isDebuggingFinest()) {
logSizes();
}
}
// TODO: if the last row or column is empty, we can do this simpler
widths.add(inc);
twidth += inc;
heights.add(inc / ratio);
theight += inc / ratio;
// Add column:
for(int y = 0; y < rows; y++) {
usage.get(y).add(null);
}
// Add row:
{
ArrayList row = new ArrayList<>();
for(int x = 0; x <= cols; x++) {
row.add(null);
}
usage.add(row);
}
assert assertConsistent();
if(LOG.isDebuggingFinest()) {
logSizes();
}
}
/**
* Get the position data of the object
*
* @param object Query object
* @return Position information: x,y,w,h
*/
public double[] get(T object) {
double[] v = map.get(object);
if(v == null) {
return null;
}
return v.clone();
}
private boolean assertConsistent() {
final int cols = widths.size();
final int rows = heights.size();
{
double wsum = 0.0;
for(int x = 0; x < cols; x++) {
assert(widths.get(x) > 0) : "Non-positive width: " + widths.get(x) + " at " + x;
wsum += widths.get(x);
}
assert(Math.abs(wsum - twidth) < 1E-10);
}
{
double hsum = 0.0;
for(int y = 0; y < rows; y++) {
assert(heights.get(y) > 0) : "Non-positive height: " + heights.get(y) + " at " + y;
hsum += heights.get(y);
}
assert(Math.abs(hsum - theight) < 1E-10);
}
{
assert(usage.size() == rows);
for(int y = 0; y < rows; y++) {
assert(usage.get(y).size() == cols);
}
}
return true;
}
/**
* Debug logging
*/
protected void logSizes() {
StringBuilder buf = new StringBuilder();
final int cols = widths.size();
final int rows = heights.size();
{
buf.append("Widths: ");
for(int x = 0; x < cols; x++) {
if(x > 0) {
buf.append(", ");
}
buf.append(widths.get(x));
}
buf.append('\n');
}
{
buf.append("Heights: ");
for(int y = 0; y < rows; y++) {
if(y > 0) {
buf.append(", ");
}
buf.append(heights.get(y));
}
buf.append('\n');
}
{
for(int y = 0; y < rows; y++) {
for(int x = 0; x < cols; x++) {
buf.append(usage.get(y).get(x) != null ? "X" : "_");
}
buf.append("|\n");
}
for(int x = 0; x < cols; x++) {
buf.append('-');
}
buf.append("+\n");
}
LOG.debug(buf);
}
/**
* Compute the relative fill. Useful for triggering a relayout if the relative
* fill is not satisfactory.
*
* @return relative fill
*/
public double relativeFill() {
double acc = 0.0;
final int cols = widths.size();
final int rows = heights.size();
{
for(int y = 0; y < rows; y++) {
for(int x = 0; x < cols; x++) {
if(usage.get(y).get(x) != null) {
acc += widths.get(x) * heights.get(y);
}
}
}
}
return acc / (twidth * theight);
}
/**
* Get the total canvas width
*
* @return Width
*/
public double getWidth() {
return twidth;
}
/**
* Get the total canvas height
*
* @return Height
*/
public double getHeight() {
return theight;
}
/**
* The items contained in the map.
*
* @return entry set
*/
public Set> entrySet() {
return Collections.unmodifiableSet(map.entrySet());
}
/**
* The item keys contained in the map.
*
* @return key set
*/
public Set keySet() {
return Collections.unmodifiableSet(map.keySet());
}
/**
* Test method.
*
* @param args
*/
public static void main(String[] args) {
LoggingConfiguration.setLevelFor(RectangleArranger.class.getName(), Level.FINEST.getName());
RectangleArranger r = new RectangleArranger<>(1.3);
r.put(4., 1., "Histogram");
r.put(4., 4., "3D view");
r.put(1., 1., "Meta 1");
r.put(1., 1., "Meta 2");
r.put(1., 1., "Meta 3");
r.put(2., 2., "Meta 4");
r.put(2., 2., "Meta 5");
r = new RectangleArranger<>(3., 3.);
r.put(1., 2., "A");
r.put(2., 1., "B");
r.put(1., 2., "C");
r.put(2., 1., "D");
r.put(2., 2., "E");
r = new RectangleArranger<>(4 - 2.6521739130434785);
r.put(4., .5, "A");
r.put(4., 3., "B");
r.put(4., 1., "C");
r.put(1., .1, "D");
}
} package-info.java 0000775 0000000 0000000 00000002004 12657057427 0035635 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/gui/overview /**
*
Classes for managing the overview plot.
*
* @apiviz.exclude java.awt.event.*
*/
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.lmu.ifi.dbs.elki.visualization.gui.overview;
package-info.java 0000775 0000000 0000000 00000001726 12657057427 0034001 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/gui /**
*
Package to provide a visualization GUI.
*
*/
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.lmu.ifi.dbs.elki.visualization.gui; elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/opticsplot/ 0000775 0000000 0000000 00000000000 12657057427 0032274 5 ustar 00root root 0000000 0000000 OPTICSCut.java 0000664 0000000 0000000 00000006765 12657057427 0034553 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/opticsplot package de.lmu.ifi.dbs.elki.visualization.opticsplot;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.algorithm.clustering.optics.ClusterOrder;
import de.lmu.ifi.dbs.elki.data.Cluster;
import de.lmu.ifi.dbs.elki.data.Clustering;
import de.lmu.ifi.dbs.elki.data.model.ClusterModel;
import de.lmu.ifi.dbs.elki.data.model.Model;
import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil;
import de.lmu.ifi.dbs.elki.database.ids.DBIDVar;
import de.lmu.ifi.dbs.elki.database.ids.ModifiableDBIDs;
/**
* Compute a partitioning from an OPTICS plot by doing a horizontal cut.
*
* @author Heidi Kolb
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.uses ClusterOrder
*/
// TODO: add non-flat clusterings
public class OPTICSCut {
/**
* Compute an OPTICS cut clustering
*
* @param co Cluster order result
* @param epsilon Epsilon value for cut
* @return New partitioning clustering
*/
public static Clustering makeOPTICSCut(E co, double epsilon) {
// Clustering model we are building
Clustering clustering = new Clustering<>("OPTICS Cut Clustering", "optics-cut");
// Collects noise elements
ModifiableDBIDs noise = DBIDUtil.newHashSet();
double lastDist = Double.MAX_VALUE;
double actDist = Double.MAX_VALUE;
// Current working set
ModifiableDBIDs current = DBIDUtil.newHashSet();
// TODO: can we implement this more nicely with a 1-lookahead?
DBIDVar prev = DBIDUtil.newVar();
for(DBIDIter it = co.iter(); it.valid(); prev.set(it), it.advance()) {
lastDist = actDist;
actDist = co.getReachability(it);
if(actDist <= epsilon) {
// the last element before the plot drops belongs to the cluster
if(lastDist > epsilon && prev.isSet()) {
// So un-noise it
noise.remove(prev);
// Add it to the cluster
current.add(prev);
}
current.add(it);
}
else {
// 'Finish' the previous cluster
if(!current.isEmpty()) {
// TODO: do we want a minpts restriction?
// But we get have only core points guaranteed anyway.
clustering.addToplevelCluster(new Cluster(current, ClusterModel.CLUSTER));
current = DBIDUtil.newHashSet();
}
// Add to noise
noise.add(it);
}
}
// Any unfinished cluster will also be added
if(!current.isEmpty()) {
clustering.addToplevelCluster(new Cluster(current, ClusterModel.CLUSTER));
}
// Add noise
clustering.addToplevelCluster(new Cluster(noise, true, ClusterModel.CLUSTER));
return clustering;
}
} OPTICSPlot.java 0000664 0000000 0000000 00000015563 12657057427 0034732 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/opticsplot package de.lmu.ifi.dbs.elki.visualization.opticsplot;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import de.lmu.ifi.dbs.elki.algorithm.clustering.optics.ClusterOrder;
import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.math.DoubleMinMax;
import de.lmu.ifi.dbs.elki.math.scales.LinearScale;
import de.lmu.ifi.dbs.elki.result.Result;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.batikutil.ThumbnailRegistryEntry;
import de.lmu.ifi.dbs.elki.visualization.style.StylingPolicy;
/**
* Class to produce an OPTICS plot image.
*
* @author Erich Schubert
* @since 0.3
*
* @apiviz.composedOf LinearScale
* @apiviz.has ClusterOrder oneway - - renders
*/
public class OPTICSPlot implements Result {
/**
* Logger
*/
private static final Logging LOG = Logging.getLogger(OPTICSPlot.class);
/**
* Minimum and maximum vertical resolution.
*/
private static final int MIN_HEIGHT = 25, MAX_HEIGHT = 300;
/**
* Scale to use
*/
LinearScale scale;
/**
* Width of plot
*/
int width;
/**
* Height of plot
*/
int height;
/**
* Ratio of plot
*/
double ratio;
/**
* The result to plot.
*/
final ClusterOrder co;
/**
* Color adapter to use
*/
final StylingPolicy colors;
/**
* The Optics plot.
*/
protected RenderedImage plot;
/**
* The plot number for Batik
*/
protected int plotnum = -1;
/**
* Constructor, with automatic distance adapter detection.
*
* @param co Cluster order to plot.
* @param colors Coloring strategy
*/
public OPTICSPlot(ClusterOrder co, StylingPolicy colors) {
super();
this.co = co;
this.colors = colors;
}
/**
* Trigger a redraw of the OPTICS plot
*/
public void replot() {
width = co.size();
height = (int) Math.ceil(width * .2);
ratio = width / (double) height;
height = height < MIN_HEIGHT ? MIN_HEIGHT : height > MAX_HEIGHT ? MAX_HEIGHT : height;
if(scale == null) {
scale = computeScale(co);
}
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
int x = 0;
for(DBIDIter it = co.iter(); it.valid(); it.advance()) {
double reach = co.getReachability(it);
final int y = scaleToPixel(reach);
try {
int col = colors.getColorForDBID(it);
for(int y2 = height - 1; y2 >= y; y2--) {
img.setRGB(x, y2, col);
}
}
catch(ArrayIndexOutOfBoundsException e) {
LOG.error("Plotting out of range: " + x + "," + y + " >= " + width + "x" + height);
}
x++;
}
plot = img;
}
/**
* Scale a reachability distance to a pixel value.
*
* @param reach Reachability
* @return Pixel value.
*/
public int scaleToPixel(double reach) {
return (Double.isInfinite(reach) || Double.isNaN(reach)) ? 0 : //
(int) Math.round(scale.getScaled(reach, height - .5, .5));
}
/**
* Scale a pixel value to a reachability
*
* @param y Pixel value
* @return Reachability
*/
public double scaleFromPixel(double y) {
return scale.getUnscaled((y - .5) / (height - 1.));
}
/**
* Compute the scale (value range)
*
* @param order Cluster order to process
* @return Scale for value range of cluster order
*/
protected LinearScale computeScale(ClusterOrder order) {
DoubleMinMax range = new DoubleMinMax();
// calculate range
for(DBIDIter it = order.iter(); it.valid(); it.advance()) {
final double reach = co.getReachability(it);
if(reach < Double.POSITIVE_INFINITY) {
range.put(reach);
}
}
// Ensure we have a valid range
if(!range.isValid()) {
range.put(0.0);
range.put(1.0);
}
return new LinearScale(range.getMin(), range.getMax());
}
/**
* @return the scale
*/
public LinearScale getScale() {
if(plot == null) {
replot();
}
return scale;
}
/**
* @return the width
*/
public int getWidth() {
if(plot == null) {
replot();
}
return width;
}
/**
* @return the height
*/
public int getHeight() {
if(plot == null) {
replot();
}
return height;
}
/**
* Get width-to-height ratio of image.
*
* @return {@code width / height}
*/
public double getRatio() {
if(plot == null) {
replot();
}
return ratio;
}
/**
* Get the OPTICS plot.
*
* @return plot image
*/
public synchronized RenderedImage getPlot() {
if(plot == null) {
replot();
}
return plot;
}
/**
* Free memory used by rendered image.
*/
public void forgetRenderedImage() {
plotnum = -1;
plot = null;
}
/**
* Get the SVG registered plot number
*
* @return Plot URI
*/
public String getSVGPlotURI() {
if(plotnum < 0) {
plotnum = ThumbnailRegistryEntry.registerImage(plot);
}
return ThumbnailRegistryEntry.INTERNAL_PREFIX + plotnum;
}
@Override
public String getLongName() {
return "OPTICS Plot";
}
@Override
public String getShortName() {
return "optics plot";
}
/**
* Static method to find an optics plot for a result, or to create a new one
* using the given context.
*
* @param co Cluster order
* @param context Context (for colors and reference clustering)
*
* @return New or existing optics plot
*/
public static OPTICSPlot plotForClusterOrder(ClusterOrder co, VisualizerContext context) {
// Check for an existing plot
// ArrayList> plots = ResultUtil.filterResults(co,
// OPTICSPlot.class);
// if (plots.size() > 0) {
// return plots.get(0);
// }
final StylingPolicy policy = context.getStylingPolicy();
OPTICSPlot opticsplot = new OPTICSPlot(co, policy);
// co.addChildResult(opticsplot);
return opticsplot;
}
/**
* Get the cluster order we are attached to.
*
* @return Cluster order
*/
public ClusterOrder getClusterOrder() {
return co;
}
}
package-info.java 0000664 0000000 0000000 00000001717 12657057427 0035412 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/opticsplot /**
*
Code for drawing OPTICS plots
*/
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.lmu.ifi.dbs.elki.visualization.opticsplot; elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/package-info.java 0000664 0000000 0000000 00000002013 12657057427 0033257 0 ustar 00root root 0000000 0000000 /**
*
Visualization package of ELKI.
*
* @apiviz.exclude elki.utilities
* @apiviz.exclude java.lang.*
*/
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.lmu.ifi.dbs.elki.visualization;
elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projections/ 0000775 0000000 0000000 00000000000 12657057427 0032433 5 ustar 00root root 0000000 0000000 AbstractFullProjection.java 0000664 0000000 0000000 00000015733 12657057427 0037653 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projections package de.lmu.ifi.dbs.elki.visualization.projections;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.math.scales.LinearScale;
import de.lmu.ifi.dbs.elki.visualization.projector.Projector;
/**
* Abstract base class for full projections.
*
* Note: the full projection API may be removed at some point, unless we find a
* clear use case that cannot be done by the low level fast projections.
*
* @author Erich Schubert
* @since 0.4.0
*/
public abstract class AbstractFullProjection extends AbstractProjection implements FullProjection {
/**
* Constructor.
*
* @param p Projector
* @param scales Scales
*/
public AbstractFullProjection(Projector p, LinearScale[] scales) {
super(p, scales);
}
/**
* Project a data vector from data space to scaled space.
*
* @param data vector in data space
* @return vector in scaled space
*/
@Override
public double[] projectDataToScaledSpace(NumberVector data) {
final int dim = data.getDimensionality();
double[] vec = new double[dim];
for(int d = 0; d < dim; d++) {
vec[d] = scales[d].getScaled(data.doubleValue(d));
}
return vec;
}
/**
* Project a data vector from data space to scaled space.
*
* @param data vector in data space
* @return vector in scaled space
*/
@Override
public double[] projectDataToScaledSpace(double[] data) {
final int dim = data.length;
double[] dst = new double[dim];
for(int d = 0; d < dim; d++) {
dst[d] = scales[d].getScaled(data[d]);
}
return dst;
}
/**
* Project a relative data vector from data space to scaled space.
*
* @param data relative vector in data space
* @return relative vector in scaled space
*/
@Override
public double[] projectRelativeDataToScaledSpace(NumberVector data) {
final int dim = data.getDimensionality();
double[] vec = new double[dim];
for(int d = 0; d < dim; d++) {
vec[d] = scales[d].getRelativeScaled(data.doubleValue(d));
}
return vec;
}
/**
* Project a relative data vector from data space to scaled space.
*
* @param data relative vector in data space
* @return relative vector in scaled space
*/
@Override
public double[] projectRelativeDataToScaledSpace(double[] data) {
final int dim = data.length;
double[] dst = new double[dim];
for(int d = 0; d < dim; d++) {
dst[d] = scales[d].getRelativeScaled(data[d]);
}
return dst;
}
/**
* Project a data vector from data space to rendering space.
*
* @param data vector in data space
* @return vector in rendering space
*/
@Override
public double[] projectDataToRenderSpace(NumberVector data) {
return projectScaledToRender(projectDataToScaledSpace(data));
}
/**
* Project a data vector from data space to rendering space.
*
* @param data vector in data space
* @return vector in rendering space
*/
@Override
public double[] projectDataToRenderSpace(double[] data) {
return projectScaledToRender(projectDataToScaledSpace(data));
}
/**
* Project a relative data vector from data space to rendering space.
*
* @param data relative vector in data space
* @return relative vector in rendering space
*/
@Override
public double[] projectRelativeDataToRenderSpace(NumberVector data) {
return projectRelativeScaledToRender(projectRelativeDataToScaledSpace(data));
}
/**
* Project a relative data vector from data space to rendering space.
*
* @param data relative vector in data space
* @return relative vector in rendering space
*/
@Override
public double[] projectRelativeDataToRenderSpace(double[] data) {
return projectRelativeScaledToRender(projectRelativeDataToScaledSpace(data));
}
/**
* Project a vector from scaled space to data space.
*
* @param Vector type
* @param v vector in scaled space
* @param factory Object factory
* @return vector in data space
*/
@Override
public NV projectScaledToDataSpace(double[] v, NumberVector.Factory factory) {
final int dim = v.length;
double[] vec = new double[dim];
for(int d = 0; d < dim; d++) {
vec[d] = scales[d].getUnscaled(v[d]);
}
return factory.newNumberVector(vec);
}
/**
* Project a vector from rendering space to data space.
*
* @param Vector type
* @param v vector in rendering space
* @param prototype Object factory
* @return vector in data space
*/
@Override
public NV projectRenderToDataSpace(double[] v, NumberVector.Factory prototype) {
final int dim = v.length;
double[] vec = projectRenderToScaled(v);
// Not calling {@link #projectScaledToDataSpace} to avoid extra copy of
// vector.
for(int d = 0; d < dim; d++) {
vec[d] = scales[d].getUnscaled(vec[d]);
}
return prototype.newNumberVector(vec);
}
/**
* Project a relative vector from scaled space to data space.
*
* @param Vector type
* @param v relative vector in scaled space
* @param prototype Object factory
* @return relative vector in data space
*/
@Override
public NV projectRelativeScaledToDataSpace(double[] v, NumberVector.Factory prototype) {
final int dim = v.length;
double[] vec = new double[dim];
for(int d = 0; d < dim; d++) {
vec[d] = scales[d].getRelativeUnscaled(v[d]);
}
return prototype.newNumberVector(vec);
}
/**
* Project a relative vector from rendering space to data space.
*
* @param Vector type
* @param v relative vector in rendering space
* @param prototype Object factory
* @return relative vector in data space
*/
@Override
public NV projectRelativeRenderToDataSpace(double[] v, NumberVector.Factory prototype) {
final int dim = v.length;
double[] vec = projectRelativeRenderToScaled(v);
// Not calling {@link #projectScaledToDataSpace} to avoid extra copy of
// vector.
for(int d = 0; d < dim; d++) {
vec[d] = scales[d].getRelativeUnscaled(vec[d]);
}
return prototype.newNumberVector(vec);
}
}
AbstractProjection.java 0000664 0000000 0000000 00000003712 12657057427 0037022 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projections package de.lmu.ifi.dbs.elki.visualization.projections;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.math.scales.LinearScale;
import de.lmu.ifi.dbs.elki.visualization.projector.Projector;
/**
* Abstract base projection class.
*
* @author Erich Schubert
* @since 0.4.0
*/
public abstract class AbstractProjection implements Projection {
/**
* Scales in data set
*/
final protected LinearScale[] scales;
/**
* Projector used
*/
final private Projector p;
/**
* Constructor.
*
* @param p Projector
* @param scales Scales to use
*/
public AbstractProjection(Projector p, LinearScale[] scales) {
super();
this.p = p;
this.scales = scales;
}
@Override
public int getInputDimensionality() {
return scales.length;
}
/**
* Get the scales used, for rendering scales mostly.
*
* @param d Dimension
* @return Scale used
*/
@Override
public LinearScale getScale(int d) {
return scales[d];
}
@Override
public String getMenuName() {
return "Projection";
}
@Override
public Projector getProjector() {
return p;
}
} AbstractSimpleProjection.java 0000664 0000000 0000000 00000005516 12657057427 0040200 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projections package de.lmu.ifi.dbs.elki.visualization.projections;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.math.linearalgebra.VMath;
import de.lmu.ifi.dbs.elki.math.scales.LinearScale;
import de.lmu.ifi.dbs.elki.visualization.projector.Projector;
/**
* Abstract base class for "simple" projections.
*
* Simple projections use the given scaling and dimension selection only.
*
* @author Erich Schubert
* @since 0.4.0
*/
public abstract class AbstractSimpleProjection extends AbstractFullProjection {
/**
* Constructor.
*
* @param p Projector
* @param scales Scales to use
*/
public AbstractSimpleProjection(Projector p, LinearScale[] scales) {
super(p, scales);
}
@Override
public double[] projectScaledToRender(double[] v) {
v = rearrange(v);
VMath.minusEquals(v, .5);
v = flipSecondEquals(v);
VMath.timesEquals(v, SCALE);
return v;
}
@Override
public double[] projectRenderToScaled(double[] v) {
v = VMath.times(v, INVSCALE);
v = flipSecondEquals(v);
VMath.plusEquals(v, .5);
v = dearrange(v);
return v;
}
@Override
public double[] projectRelativeScaledToRender(double[] v) {
v = rearrange(v);
v = flipSecondEquals(v);
VMath.timesEquals(v, SCALE);
return v;
}
@Override
public double[] projectRelativeRenderToScaled(double[] v) {
v = VMath.times(v, INVSCALE);
v = flipSecondEquals(v);
v = dearrange(v);
return v;
}
/**
* Flip the y axis.
*
* @param v double[]
* @return modified v
*/
protected double[] flipSecondEquals(double[] v) {
if(v.length > 1) {
v[1] *= -1;
}
return v;
}
/**
* Method to rearrange components.
*
* @param v double[] to rearrange
* @return rearranged copy
*/
protected abstract double[] rearrange(double[] v);
/**
* Undo the rearrangement of components.
*
* @param v double[] to undo the rearrangement
* @return rearranged-undone copy
*/
protected abstract double[] dearrange(double[] v);
} AffineProjection.java 0000664 0000000 0000000 00000020374 12657057427 0036452 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projections package de.lmu.ifi.dbs.elki.visualization.projections;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.Arrays;
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.math.DoubleMinMax;
import de.lmu.ifi.dbs.elki.math.linearalgebra.AffineTransformation;
import de.lmu.ifi.dbs.elki.math.scales.LinearScale;
import de.lmu.ifi.dbs.elki.utilities.BitsUtil;
import de.lmu.ifi.dbs.elki.visualization.projector.Projector;
/**
* Affine projections are the most general class. They are initialized by an
* arbitrary affine transformation matrix, and can thus represent any rotation
* and scaling, even simple perspective projections.
*
* However, this comes at the cost of a matrix multiplication.
*
* @author Erich Schubert
* @since 0.4.0
*/
public class AffineProjection extends AbstractFullProjection implements Projection2D {
/**
* Affine transformation used in projection
*/
private AffineTransformation proj;
/**
* Viewport (cache)
*/
private CanvasSize viewport = null;
/**
* Constructor with a given database and axes.
*
* @param p Projector
* @param scales Scales to use
* @param proj Projection to use
*/
public AffineProjection(Projector p, LinearScale[] scales, AffineTransformation proj) {
super(p, scales);
this.proj = proj;
}
/**
* Project a vector from scaled space to rendering space.
*
* @param v vector in scaled space
* @return vector in rendering space
*/
@Override
public double[] projectScaledToRender(double[] v) {
return proj.apply(v);
}
/**
* Project a vector from rendering space to scaled space.
*
* @param v vector in rendering space
* @return vector in scaled space
*/
@Override
public double[] projectRenderToScaled(double[] v) {
return proj.applyInverse(v);
}
/**
* Project a relative vector from scaled space to rendering space.
*
* @param v relative vector in scaled space
* @return relative vector in rendering space
*/
@Override
public double[] projectRelativeScaledToRender(double[] v) {
return proj.applyRelative(v);
}
/**
* Project a relative vector from rendering space to scaled space.
*
* @param v relative vector in rendering space
* @return relative vector in scaled space
*/
@Override
public double[] projectRelativeRenderToScaled(double[] v) {
return proj.applyRelativeInverse(v);
}
@Override
public CanvasSize estimateViewport() {
if(viewport == null) {
final int dim = proj.getDimensionality();
DoubleMinMax minmaxx = new DoubleMinMax();
DoubleMinMax minmaxy = new DoubleMinMax();
// Origin
final double[] vec = new double[dim];
double[] orig = projectScaledToRender(vec);
minmaxx.put(orig[0]);
minmaxy.put(orig[1]);
// Diagonal point
Arrays.fill(vec, 1.);
double[] diag = projectScaledToRender(vec);
minmaxx.put(diag[0]);
minmaxy.put(diag[1]);
// Axis end points
for(int d = 0; d < dim; d++) {
Arrays.fill(vec, 0.);
vec[d] = 1.;
double[] ax = projectScaledToRender(vec);
minmaxx.put(ax[0]);
minmaxy.put(ax[1]);
}
viewport = new CanvasSize(minmaxx.getMin(), minmaxx.getMax(), minmaxy.getMin(), minmaxy.getMax());
}
return viewport;
}
/**
* Compute an transformation matrix to show only axis ax1 and ax2.
*
* @param dim Dimensionality
* @param ax1 First axis
* @param ax2 Second axis
* @return transformation matrix
*/
public static AffineTransformation axisProjection(int dim, int ax1, int ax2) {
// setup a projection to get the data into the interval -1:+1 in each
// dimension with the intended-to-see dimensions first.
AffineTransformation proj = AffineTransformation.reorderAxesTransformation(dim, new int[] { ax1, ax2 });
// Assuming that the data was normalized on [0:1], center it:
double[] trans = new double[dim];
for(int i = 0; i < dim; i++) {
trans[i] = -.5;
}
proj.addTranslation(trans);
// mirror on the y axis, since the SVG coordinate system is screen
// coordinates (y = down) and not mathematical coordinates (y = up)
proj.addAxisReflection(2);
// scale it up
proj.addScaling(SCALE);
return proj;
}
@Override
public double[] fastProjectDataToRenderSpace(double[] data) {
return fastProjectScaledToRenderSpace(fastProjectDataToScaledSpace(data));
}
@Override
public double[] fastProjectDataToRenderSpace(NumberVector data) {
return fastProjectScaledToRenderSpace(fastProjectDataToScaledSpace(data));
}
@Override
public double[] fastProjectDataToScaledSpace(double[] data) {
return projectDataToScaledSpace(data);
}
@Override
public double[] fastProjectDataToScaledSpace(NumberVector data) {
return projectDataToScaledSpace(data);
}
@Override
public double[] fastProjectScaledToRenderSpace(double[] vr) {
double x = 0.0;
double y = 0.0;
double s = 0.0;
final double[][] matrix = proj.getTransformation().getArrayRef();
final double[] colx = matrix[0];
final double[] coly = matrix[1];
final double[] cols = matrix[vr.length];
assert (colx.length == coly.length && colx.length == cols.length && cols.length == vr.length + 1);
for(int k = 0; k < vr.length; k++) {
x += colx[k] * vr[k];
y += coly[k] * vr[k];
s += cols[k] * vr[k];
}
// add homogene component:
x += colx[vr.length];
y += coly[vr.length];
s += cols[vr.length];
// Note: we may have NaN values here.
// assert (s > 0.0 || s < 0.0);
return new double[] { x / s, y / s };
}
@Override
public double[] fastProjectRelativeDataToRenderSpace(double[] data) {
return fastProjectRelativeScaledToRenderSpace(projectRelativeDataToScaledSpace(data));
}
@Override
public double[] fastProjectRelativeDataToRenderSpace(NumberVector data) {
// FIXME: implement with less objects?
return fastProjectRelativeScaledToRenderSpace(projectRelativeDataToScaledSpace(data));
}
@Override
public double[] fastProjectRelativeScaledToRenderSpace(double[] vr) {
double x = 0.0;
double y = 0.0;
final double[][] matrix = proj.getTransformation().getArrayRef();
final double[] colx = matrix[0];
final double[] coly = matrix[1];
assert (colx.length == coly.length);
for(int k = 0; k < vr.length; k++) {
x += colx[k] * vr[k];
y += coly[k] * vr[k];
}
return new double[] { x, y };
}
@Override
public double[] fastProjectRenderToDataSpace(double x, double y) {
double[] ret = fastProjectRenderToScaledSpace(x, y);
for(int d = 0; d < scales.length; d++) {
ret[d] = scales[d].getUnscaled(ret[d]);
}
return ret;
}
@Override
public double[] fastProjectRenderToScaledSpace(double x, double y) {
double[] c = new double[scales.length];
c[0] = x;
c[1] = y;
Arrays.fill(c, 2, scales.length, 0.5);
return projectRenderToScaled(c);
}
@Override
public long[] getVisibleDimensions2D() {
final int dim = proj.getDimensionality();
long[] actDim = BitsUtil.zero(dim);
double[] vScale = new double[dim];
for(int d = 0; d < dim; d++) {
Arrays.fill(vScale, 0);
vScale[d] = 1;
double[] vRender = fastProjectScaledToRenderSpace(vScale);
// TODO: Can't we do this by inspecting the projection matrix directly?
if(vRender[0] > 0.0 || vRender[0] < 0.0 || vRender[1] != 0) {
BitsUtil.setI(actDim, d);
}
}
return actDim;
}
}
CanvasSize.java 0000664 0000000 0000000 00000005777 12657057427 0035305 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projections package de.lmu.ifi.dbs.elki.visualization.projections;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
/**
* Size of a canvas. A 2D bounding rectangle.
*
* @author Erich Schubert
* @since 0.5.0
*/
public class CanvasSize {
/**
* Minimum X
*/
public final double minx;
/**
* Maximum X
*/
public final double maxx;
/**
* Minimum Y
*/
public final double miny;
/**
* Maximum Y
*/
public final double maxy;
/**
* Constructor.
*
* @param minx Minimum X
* @param maxx Maximum X
* @param miny Minimum Y
* @param maxy Maximum Y
*/
public CanvasSize(double minx, double maxx, double miny, double maxy) {
super();
this.minx = minx;
this.maxx = maxx;
this.miny = miny;
this.maxy = maxy;
}
/**
* @return the mininum X
*/
public double getMinX() {
return minx;
}
/**
* @return the maximum X
*/
public double getMaxX() {
return maxx;
}
/**
* @return the minimum Y
*/
public double getMinY() {
return miny;
}
/**
* @return the maximum Y
*/
public double getMaxY() {
return maxy;
}
/**
* @return the length on X
*/
public double getDiffX() {
return maxx - minx;
}
/**
* @return the length on Y
*/
public double getDiffY() {
return maxy - miny;
}
/**
* Continue a line along a given direction to the margin.
*
* @param origin Origin point
* @param delta Direction vector
* @return scaling factor for delta vector
*/
public double continueToMargin(double[] origin, double[] delta) {
assert (delta.length == 2 && origin.length == 2);
double factor = Double.POSITIVE_INFINITY;
if(delta[0] > 0) {
factor = Math.min(factor, (maxx - origin[0]) / delta[0]);
}
else if(delta[0] < 0) {
factor = Math.min(factor, (origin[0] - minx) / -delta[0]);
}
if(delta[1] > 0) {
factor = Math.min(factor, (maxy - origin[1]) / delta[1]);
}
else if(delta[1] < 0) {
factor = Math.min(factor, (origin[1] - miny) / -delta[1]);
}
return factor;
}
@Override
public String toString() {
return "CanvasSize[x=" + minx + ":" + maxx + ", y=" + miny + ":" + maxy + "]";
}
} FullProjection.java 0000664 0000000 0000000 00000012536 12657057427 0036165 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projections package de.lmu.ifi.dbs.elki.visualization.projections;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.data.NumberVector;
/**
* Full vector space projections.
*
* These rather portable projections offer a large choice of functions, at the
* cost of often being a bit slower than the low level functions.
*
* Note: this interface and methods may be removed, unless there is a clear use
* case for them as opposed to always using the low-level fast projections.
*
* @author Erich Schubert
* @since 0.4.0
*/
public interface FullProjection extends Projection {
/**
* Project a vector from scaled space to rendering space.
*
* @param v vector in scaled space
* @return vector in rendering space
*/
double[] projectScaledToRender(double[] v);
/**
* Project a vector from rendering space to scaled space.
*
* @param v vector in rendering space
* @return vector in scaled space
*/
double[] projectRenderToScaled(double[] v);
/**
* Project a relative vector from scaled space to rendering space.
*
* @param v relative vector in scaled space
* @return relative vector in rendering space
*/
double[] projectRelativeScaledToRender(double[] v);
/**
* Project a relative vector from rendering space to scaled space.
*
* @param v relative vector in rendering space
* @return relative vector in scaled space
*/
double[] projectRelativeRenderToScaled(double[] v);
/**
* Project a data vector from data space to scaled space.
*
* @param data vector in data space
* @return vector in scaled space
*/
double[] projectDataToScaledSpace(NumberVector data);
/**
* Project a data vector from data space to scaled space.
*
* @param data vector in data space
* @return vector in scaled space
*/
double[] projectDataToScaledSpace(double[] data);
/**
* Project a relative data vector from data space to scaled space.
*
* @param data relative vector in data space
* @return relative vector in scaled space
*/
double[] projectRelativeDataToScaledSpace(NumberVector data);
/**
* Project a relative data vector from data space to scaled space.
*
* @param data relative vector in data space
* @return relative vector in scaled space
*/
double[] projectRelativeDataToScaledSpace(double[] data);
/**
* Project a data vector from data space to rendering space.
*
* @param data vector in data space
* @return vector in rendering space
*/
double[] projectDataToRenderSpace(NumberVector data);
/**
* Project a data vector from data space to rendering space.
*
* @param data vector in data space
* @return vector in rendering space
*/
double[] projectDataToRenderSpace(double[] data);
/**
* Project a vector from scaled space to data space.
*
* @param double[] type
* @param v vector in scaled space
* @param factory Object factory
* @return vector in data space
*/
NV projectScaledToDataSpace(double[] v, NumberVector.Factory factory);
/**
* Project a vector from rendering space to data space.
*
* @param double[] type
* @param v vector in rendering space
* @param prototype Object factory
* @return vector in data space
*/
NV projectRenderToDataSpace(double[] v, NumberVector.Factory prototype);
/**
* Project a relative data vector from data space to rendering space.
*
* @param data relative vector in data space
* @return relative vector in rendering space
*/
double[] projectRelativeDataToRenderSpace(NumberVector data);
/**
* Project a relative data vector from data space to rendering space.
*
* @param data relative vector in data space
* @return relative vector in rendering space
*/
double[] projectRelativeDataToRenderSpace(double[] data);
/**
* Project a relative vector from scaled space to data space.
*
* @param double[] type
* @param v relative vector in scaled space
* @param prototype Object factory
* @return relative vector in data space
*/
NV projectRelativeScaledToDataSpace(double[] v, NumberVector.Factory prototype);
/**
* Project a relative vector from rendering space to data space.
*
* @param double[] type
* @param v relative vector in rendering space
* @param prototype Object factory
* @return relative vector in data space
*/
NV projectRelativeRenderToDataSpace(double[] v, NumberVector.Factory prototype);
}
OPTICSProjection.java 0000664 0000000 0000000 00000004735 12657057427 0036266 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projections package de.lmu.ifi.dbs.elki.visualization.projections;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.algorithm.clustering.optics.ClusterOrder;
import de.lmu.ifi.dbs.elki.math.scales.LinearScale;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.opticsplot.OPTICSPlot;
import de.lmu.ifi.dbs.elki.visualization.projector.OPTICSProjector;
import de.lmu.ifi.dbs.elki.visualization.projector.Projector;
/**
* OPTICS projection. This is not really needed, but a quick hack to have more
* consistency in the visualizer API.
*
* @author Erich Schubert
* @since 0.4.0
*/
public class OPTICSProjection implements Projection {
/**
* The projector we were generated from.
*/
OPTICSProjector projector;
/**
* Constructor.
*
* @param opticsProjector OPTICS projector
*/
public OPTICSProjection(OPTICSProjector opticsProjector) {
super();
this.projector = opticsProjector;
}
@Override
public String getMenuName() {
return "OPTICS Plot Projection";
}
@Override
public int getInputDimensionality() {
return -1;
}
@Override
public LinearScale getScale(int d) {
return null;
}
/**
* Get or produce the actual OPTICS plot.
*
* @param context Context to use
* @return Plot
*/
public OPTICSPlot getOPTICSPlot(VisualizerContext context) {
return projector.getOPTICSPlot(context);
}
/**
* Get the OPTICS cluster order.
*
* @return Cluster oder result.
*/
public ClusterOrder getResult() {
return projector.getResult();
}
@Override
public Projector getProjector() {
return projector;
}
}
Projection.java 0000664 0000000 0000000 00000004305 12657057427 0035335 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projections package de.lmu.ifi.dbs.elki.visualization.projections;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.math.scales.LinearScale;
import de.lmu.ifi.dbs.elki.visualization.VisualizationItem;
import de.lmu.ifi.dbs.elki.visualization.projector.Projector;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
/**
* Base interface used for projections in the ELKI visualizers.
*
* There are specialized interfaces for 1D and 2D that only compute the
* projections in the required dimensions!
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.landmark
*
* @apiviz.composedOf LinearScale
*/
public interface Projection extends VisualizationItem {
/**
* Scaling constant. Keep in sync with
* {@link de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary#SCALE}.
*/
public static final double SCALE = StyleLibrary.SCALE;
/**
* Inverse scaling constant.
*/
public static final double INVSCALE = 1. / SCALE;
/**
* Get the input dimensionality of the projection.
*
* @return Input dimensionality
*/
public int getInputDimensionality();
/**
* Get the scale class for a particular dimension.
*
* @param d Dimension
* @return Scale class
*/
public LinearScale getScale(int d);
/**
* Projector used for generating this projection.
*
* @return Projector
*/
public Projector getProjector();
} Projection1D.java 0000664 0000000 0000000 00000004760 12657057427 0035527 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projections package de.lmu.ifi.dbs.elki.visualization.projections;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.data.NumberVector;
/**
* Interface for projections that have a specialization to only compute the
* first component.
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.landmark
*/
public interface Projection1D extends Projection {
/**
* Project a data vector from data space to rendering space.
*
* @param data vector in data space
* @return vector in rendering space
*/
public double fastProjectDataToRenderSpace(double[] data);
/**
* Project a data vector from data space to rendering space.
*
* @param data vector in data space
* @return vector in rendering space
*/
public double fastProjectDataToRenderSpace(NumberVector data);
/**
* Project a vector from scaled space to rendering space.
*
* @param v vector in scaled space
* @return vector in rendering space
*/
public double fastProjectScaledToRender(double[] v);
/**
* Project a data vector from data space to rendering space.
*
* @param data vector in data space
* @return vector in rendering space
*/
public double fastProjectRelativeDataToRenderSpace(double[] data);
/**
* Project a data vector from data space to rendering space.
*
* @param data vector in data space
* @return vector in rendering space
*/
public double fastProjectRelativeDataToRenderSpace(NumberVector data);
/**
* Project a vector from scaled space to rendering space.
*
* @param v vector in scaled space
* @return vector in rendering space
*/
public double fastProjectRelativeScaledToRender(double[] v);
} Projection2D.java 0000664 0000000 0000000 00000010161 12657057427 0035520 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projections package de.lmu.ifi.dbs.elki.visualization.projections;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.data.NumberVector;
/**
* Projections that have specialized methods to only compute the first two
* dimensions of the projection.
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.landmark
*
* @apiviz.has CanvasSize
*/
public interface Projection2D extends Projection {
/**
* Project a data vector from data space to rendering space.
*
* @param data vector in data space
* @return vector in rendering space
*/
public double[] fastProjectDataToRenderSpace(double[] data);
/**
* Project a data vector from data space to rendering space.
*
* @param data vector in data space
* @return vector in rendering space
*/
public double[] fastProjectDataToRenderSpace(NumberVector data);
/**
* Project a data vector from data space to scaled space.
*
* @param data vector in data space
* @return vector in scaled space
*/
public double[] fastProjectDataToScaledSpace(double[] data);
/**
* Project a data vector from data space to scaled space.
*
* @param data vector in data space
* @return vector in scaled space
*/
public double[] fastProjectDataToScaledSpace(NumberVector data);
/**
* Project a vector from scaled space to rendering space.
*
* @param v vector in scaled space
* @return vector in rendering space
*/
public double[] fastProjectScaledToRenderSpace(double[] v);
/**
* Project a data vector from rendering space to data space.
*
* @param x X coordinate
* @param y Y coordinate
* @return vector in data space
*/
public double[] fastProjectRenderToDataSpace(double x, double y);
/**
* Project a data vector from rendering space to data space.
*
* @param data vector in rendering space
* @param prototype Prototype to create vector from
* @return vector in data space
*/
// public V fastProjectRenderToDataSpace(double[]
// data, V prototype);
/**
* Project a vector from rendering space to scaled space.
*
* @param x X coordinate
* @param y Y coordinate
* @return vector in scaled space
*/
public double[] fastProjectRenderToScaledSpace(double x, double y);
/**
* Project a data vector from data space to rendering space.
*
* @param data vector in data space
* @return vector in rendering space
*/
public double[] fastProjectRelativeDataToRenderSpace(double[] data);
/**
* Project a data vector from data space to rendering space.
*
* @param data vector in data space
* @return vector in rendering space
*/
public double[] fastProjectRelativeDataToRenderSpace(NumberVector data);
/**
* Project a vector from scaled space to rendering space.
*
* @param v vector in scaled space
* @return vector in rendering space
*/
public double[] fastProjectRelativeScaledToRenderSpace(double[] v);
// FIXME: add missing relative projection functions
/**
* Estimate the viewport requirements
*
* @return Canvas size obtained from projecting scale endpoints
*/
public CanvasSize estimateViewport();
/**
* Get a bit set of dimensions that are visible.
*
* @return Bit set, first dimension is bit 0.
*/
public long[] getVisibleDimensions2D();
}
ProjectionParallel.java 0000664 0000000 0000000 00000011673 12657057427 0037020 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projections package de.lmu.ifi.dbs.elki.visualization.projections;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.math.scales.LinearScale;
/**
* Projection to parallel coordinates that allows reordering and inversion of
* axes.
*
* Note: when using this projection, pay attention to the two different schemes
* of dimension numbering: by input dimension and by axis position.
*
* @author Robert Rödler
* @author Erich Schubert
* @since 0.5.0
*/
public interface ProjectionParallel extends Projection {
/**
* Get inversion flag of axis.
*
* @param axis Axis (reordered) position
* @return Inversion flag
*/
public boolean isAxisInverted(int axis);
/**
* Set inversion flag of axis.
*
* @param axis Axis (reordered) position
* @param bool Value of inversion flag
*/
public void setAxisInverted(int axis, boolean bool);
/**
* Toggle inverted flag of axis.
*
* @param axis Axis (reordered) position
*/
public void toggleAxisInverted(int axis);
/**
* Get inversion flag of dimension.
*
* @param truedim Dimension in original numbering
* @return Inversion flag
*/
public boolean isDimInverted(int truedim);
/**
* Set inversion flag of a dimension.
*
* @param truedim Dimension in original numbering
* @param bool Value of inversion flag
*/
public void setDimInverted(int truedim, boolean bool);
/**
* Toggle inverted flag of dimension.
*
* @param truedim Dimension in original numbering
*/
public void toggleDimInverted(int truedim);
/**
* Get scale for the given axis
*
* @param axis Axis (reordered) position
* @return Axis scale
*/
public LinearScale getAxisScale(int axis);
/**
* Test whether the current axis is visible
*
* @param axis Axis (reordered) position
* @return Visibility of axis
*/
public boolean isAxisVisible(int axis);
/**
* Set the visibility of the axis.
*
* @param axis Axis number
* @param vis Visibility status
*/
public void setAxisVisible(int axis, boolean vis);
/**
* Toggle visibility of the axis.
*
* @param axis Axis number
*/
public void toggleAxisVisible(int axis);
/**
* Get the number of visible dimension.
*
* @return Number of visible dimensions
*/
public int getVisibleDimensions();
/**
* Exchange axes A and B
* @param a First axis
* @param b Second axis
*/
public void swapAxes(int a, int b);
/**
* shift a dimension to another position
*
* @param axis axis to shift
* @param rn new position
*/
public void moveAxis(int axis, int rn);
/**
* Get the dimension for the given axis number
*
* @param axis Axis number
* @return Dimension
*/
public int getDimForAxis(int axis);
/**
* Get the dimension for the given visible axis
*
* @param axis Axis number (visible axes only)
* @return Dimension
*/
public int getDimForVisibleAxis(int axis);
/**
* Fast project a vector from data to render space
*
* @param v Input vector
* @return Vector with reordering, inversions and scales applied.
*/
public double[] fastProjectDataToRenderSpace(double[] v);
/**
* Fast project a vector from data to render space
*
* @param v Input vector
* @return Vector with reordering, inversions and scales applied.
*/
public double[] fastProjectDataToRenderSpace(NumberVector v);
/**
* Project the value of a single axis to its display value
*
* @param value Input value
* @param axis Axis to use for scaling and inversion
* @return Transformed value
*/
public double fastProjectDataToRenderSpace(double value, int axis);
/**
* Project a display value back to the original data space
*
* @param value transformed value
* @param axis Axis to use for scaling and inversion
* @return Original value
*/
public double fastProjectRenderToDataSpace(double value, int axis);
/**
* Find the axis assigned to the given dimension.
*
* @param truedim Dimension
* @return Axis number
*/
public int getAxisForDim(int truedim);
} Simple1D.java 0000664 0000000 0000000 00000006102 12657057427 0034634 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projections package de.lmu.ifi.dbs.elki.visualization.projections;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.math.scales.LinearScale;
import de.lmu.ifi.dbs.elki.visualization.projector.Projector;
/**
* Dimension-selecting 1D projection.
*
* @author Erich Schubert
* @since 0.4.0
*/
public class Simple1D extends AbstractSimpleProjection implements Projection1D {
/**
* Our dimension, starting with 0
*/
final int dnum;
/**
* Simple 1D projection using scaling only.
*
* @param p Projector
* @param scales Scales to use
* @param dnum Dimension (starting at 0)
*/
public Simple1D(Projector p, LinearScale[] scales, int dnum) {
super(p, scales);
this.dnum = dnum;
}
@Override
public double fastProjectDataToRenderSpace(double[] data) {
return (scales[dnum].getScaled(data[dnum]) - 0.5) * SCALE;
}
@Override
public double fastProjectDataToRenderSpace(NumberVector data) {
return (scales[dnum].getScaled(data.doubleValue(dnum)) - 0.5) * SCALE;
}
@Override
public double fastProjectScaledToRender(double[] v) {
return (v[dnum] - 0.5) * SCALE;
}
@Override
public double fastProjectRelativeDataToRenderSpace(double[] data) {
return (scales[dnum].getScaled(data[dnum]) - 0.5) * SCALE;
}
@Override
public double fastProjectRelativeDataToRenderSpace(NumberVector data) {
return (data.doubleValue(dnum) - 0.5) * SCALE;
}
@Override
public double fastProjectRelativeScaledToRender(double[] v) {
return v[dnum] * SCALE;
}
@Override
protected double[] rearrange(double[] v) {
final double[] r = new double[v.length];
r[0] = v[dnum];
if(dnum > 0) {
System.arraycopy(v, 0, r, 1, dnum);
}
if(dnum + 1 < v.length) {
System.arraycopy(v, dnum + 1, r, dnum + 1, v.length - (dnum + 1));
}
return r;
}
@Override
protected double[] dearrange(double[] v) {
final double[] r = new double[v.length];
if(dnum > 0) {
System.arraycopy(v, 1, r, 0, dnum);
}
r[dnum] = v[0];
if(dnum + 1 < v.length) {
System.arraycopy(v, dnum + 1, r, dnum + 1, v.length - (dnum + 1));
}
return r;
}
@Override
public String getMenuName() {
return "Axis";
}
} Simple2D.java 0000664 0000000 0000000 00000013603 12657057427 0034641 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projections package de.lmu.ifi.dbs.elki.visualization.projections;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.math.scales.LinearScale;
import de.lmu.ifi.dbs.elki.utilities.BitsUtil;
import de.lmu.ifi.dbs.elki.visualization.projector.Projector;
/**
* Dimension-selecting 2D projection.
*
* @author Erich Schubert
* @since 0.4.0
*/
public class Simple2D extends AbstractSimpleProjection implements Projection2D {
/**
* Dimensions for fast projection mode.
*/
private int dim1;
/**
* Dimensions for fast projection mode.
*/
private int dim2;
/**
* Constructor with a given database and axes.
*
* @param p Projector
* @param scales Scales to use
* @param ax1 First axis
* @param ax2 Second axis
*/
public Simple2D(Projector p, LinearScale[] scales, int ax1, int ax2) {
super(p, scales);
this.dim1 = ax1;
this.dim2 = ax2;
}
@Override
public double[] fastProjectDataToRenderSpace(double[] data) {
double x = (scales[dim1].getScaled(data[dim1]) - 0.5) * SCALE;
double y = (scales[dim2].getScaled(data[dim2]) - 0.5) * -SCALE;
return new double[] { x, y };
}
@Override
public double[] fastProjectDataToRenderSpace(NumberVector data) {
double x = (scales[dim1].getScaled(data.doubleValue(dim1)) - 0.5) * SCALE;
double y = (scales[dim2].getScaled(data.doubleValue(dim2)) - 0.5) * -SCALE;
return new double[] { x, y };
}
@Override
public double[] fastProjectDataToScaledSpace(double[] data) {
final int dim = data.length;
double[] ds = new double[dim];
for(int d = 0; d < dim; d++) {
ds[d] = scales[d].getScaled(data[d]);
}
return ds;
}
@Override
public double[] fastProjectDataToScaledSpace(NumberVector data) {
final int dim = data.getDimensionality();
double[] ds = new double[dim];
for(int d = 0; d < dim; d++) {
ds[d] = scales[d].getScaled(data.doubleValue(d));
}
return ds;
}
@Override
public double[] fastProjectScaledToRenderSpace(double[] v) {
double x = (v[dim1] - 0.5) * SCALE;
double y = (v[dim2] - 0.5) * -SCALE;
return new double[] { x, y };
}
@Override
public double[] fastProjectRenderToDataSpace(double x, double y) {
double[] ret = new double[scales.length];
for(int d = 0; d < scales.length; d++) {
ret[d] = //
(d == dim1) ? scales[d].getUnscaled((x * INVSCALE) + 0.5) : //
(d == dim2) ? scales[d].getUnscaled((y * -INVSCALE) + 0.5) : //
scales[d].getUnscaled(0.5);
}
return ret;
}
@Override
public double[] fastProjectRenderToScaledSpace(double x, double y) {
double[] ret = new double[scales.length];
for(int d = 0; d < scales.length; d++) {
ret[d] = //
(d == dim1) ? (x * INVSCALE) + 0.5 : //
(d == dim2) ? (y * -INVSCALE) + 0.5 : //
0.5;
}
return ret;
}
@Override
public double[] fastProjectRelativeDataToRenderSpace(double[] data) {
double x = scales[dim1].getRelativeScaled(data[dim1]) * SCALE;
double y = scales[dim2].getRelativeScaled(data[dim2]) * -SCALE;
return new double[] { x, y };
}
@Override
public double[] fastProjectRelativeDataToRenderSpace(NumberVector data) {
double x = scales[dim1].getRelativeScaled(data.doubleValue(dim1)) * SCALE;
double y = scales[dim2].getRelativeScaled(data.doubleValue(dim2)) * -SCALE;
return new double[] { x, y };
}
@Override
public double[] fastProjectRelativeScaledToRenderSpace(double[] vr) {
double x = vr[dim1] * SCALE;
double y = vr[dim2] * -SCALE;
return new double[] { x, y };
}
@Override
public long[] getVisibleDimensions2D() {
long[] actDim = new long[super.scales.length];
BitsUtil.setI(actDim, dim1);
BitsUtil.setI(actDim, dim2);
return actDim;
}
@Override
public CanvasSize estimateViewport() {
return new CanvasSize(-SCALE * .5, SCALE * .5, -SCALE * .5, SCALE * .5);
}
@Override
protected double[] rearrange(double[] v) {
final double[] r = new double[v.length];
r[0] = v[dim1];
r[1] = v[dim2];
final int ldim = Math.min(dim1, dim2);
final int hdim = Math.max(dim1, dim2);
if(ldim > 0) {
System.arraycopy(v, 0, r, 2, ldim);
}
if(hdim - ldim > 1) {
System.arraycopy(v, ldim + 1, r, ldim + 2, hdim - (ldim + 1));
}
if(hdim + 1 < v.length) {
System.arraycopy(v, hdim + 1, r, hdim + 1, v.length - (hdim + 1));
}
return r;
}
@Override
protected double[] dearrange(double[] v) {
final double[] r = new double[v.length];
r[dim1] = v[0];
r[dim2] = v[1];
// copy remainder
final int ldim = Math.min(dim1, dim2);
final int hdim = Math.max(dim1, dim2);
if(ldim > 0) {
System.arraycopy(v, 2, r, 0, ldim);
}
// ldim = s[0 or 1]
if(hdim - ldim > 1) {
System.arraycopy(v, ldim + 2, r, ldim + 1, hdim - (ldim + 1));
}
// hdim = s[0 or 1]
if(hdim + 1 < v.length) {
System.arraycopy(v, hdim + 1, r, hdim + 1, v.length - (hdim + 1));
}
return r;
}
@Override
public String getMenuName() {
return "Scatterplot";
}
} SimpleParallel.java 0000664 0000000 0000000 00000015066 12657057427 0036135 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projections package de.lmu.ifi.dbs.elki.visualization.projections;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.math.scales.LinearScale;
import de.lmu.ifi.dbs.elki.visualization.projector.Projector;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
/**
* Simple parallel projection
*
* Scaled space: reordered, scaled and inverted. Lower dimensionality! [0:1]
* Render space: not used here; no recentering needed.
*
* @author Robert Rödler
* @author Erich Schubert
* @since 0.5.0
*/
public class SimpleParallel implements ProjectionParallel {
/**
* Number of visible dimensions
*/
int visDims;
/**
* Flags for the dimensions
*/
byte[] flags;
/**
* Ordering of dimensions
*/
int[] dimOrder;
/**
* Scales
*/
private LinearScale[] scales;
/**
* Projector
*/
private Projector p;
/**
* Flag for visibility
*/
final static byte FLAG_HIDDEN = 1;
/**
* Flag for inverted dimensions
*
* TODO: handle inversions via scales?
*/
final static byte FLAG_INVERTED = 2;
/**
* Constructor.
*
* @param p Projector
* @param scales Scales to use
*/
public SimpleParallel(Projector p, LinearScale[] scales) {
super();
this.p = p;
this.scales = scales;
visDims = scales.length;
flags = new byte[scales.length];
dimOrder = new int[scales.length];
for(int i = 0; i < dimOrder.length; i++) {
dimOrder[i] = i;
}
}
@Override
public LinearScale getScale(int dim) {
return scales[dim];
}
@Override
public boolean isAxisInverted(int axis) {
return isDimInverted(dimOrder[axis]);
}
@Override
public void setAxisInverted(int axis, boolean bool) {
setDimInverted(dimOrder[axis], bool);
}
@Override
public void toggleAxisInverted(int axis) {
toggleDimInverted(dimOrder[axis]);
}
@Override
public boolean isDimInverted(int truedim) {
return (flags[truedim] & FLAG_INVERTED) == FLAG_INVERTED;
}
@Override
public void setDimInverted(int truedim, boolean bool) {
if(bool) {
flags[truedim] |= FLAG_INVERTED;
}
else {
flags[truedim] &= ~FLAG_INVERTED;
}
}
@Override
public void toggleDimInverted(int truedim) {
flags[truedim] ^= FLAG_INVERTED;
}
@Override
public LinearScale getAxisScale(int axis) {
return scales[dimOrder[axis]];
}
protected boolean isDimHidden(int truedim) {
return (flags[truedim] & FLAG_HIDDEN) == FLAG_HIDDEN;
}
@Override
public boolean isAxisVisible(int dim) {
return !isDimHidden(dimOrder[dim]);
}
@Override
public void setAxisVisible(int dim, boolean vis) {
boolean prev = isAxisVisible(dim);
if(prev == vis) {
return;
}
if(vis) {
flags[dimOrder[dim]] &= ~FLAG_HIDDEN;
visDims++;
}
else {
flags[dimOrder[dim]] |= FLAG_HIDDEN;
visDims--;
}
}
@Override
public void toggleAxisVisible(int dim) {
boolean prev = isAxisVisible(dim);
if(!prev) {
flags[dimOrder[dim]] &= ~FLAG_HIDDEN;
visDims++;
}
else {
flags[dimOrder[dim]] |= FLAG_HIDDEN;
visDims--;
}
}
@Override
public int getVisibleDimensions() {
return visDims;
}
@Override
public int getDimForAxis(int pos) {
return dimOrder[pos];
}
@Override
public int getDimForVisibleAxis(int pos) {
for(int i = 0; i < scales.length; i++) {
if(isDimHidden(dimOrder[i])) {
continue;
}
if(pos == 0) {
return dimOrder[i];
}
pos--;
}
return -1;
}
@Override
public void swapAxes(int a, int b) {
int temp = dimOrder[a];
dimOrder[a] = dimOrder[b];
dimOrder[b] = temp;
}
@Override
public void moveAxis(int src, int dest) {
if(src > dest) {
int temp = dimOrder[src];
System.arraycopy(dimOrder, dest, dimOrder, dest + 1, src - dest);
dimOrder[dest] = temp;
}
else if(src < dest) {
int temp = dimOrder[src];
System.arraycopy(dimOrder, src + 1, dimOrder, src, dest - src);
dimOrder[dest - 1] = temp;
}
}
@Override
public double[] fastProjectDataToRenderSpace(NumberVector data) {
double[] v = new double[visDims];
for(int j = 0, o = 0; j < scales.length; j++) {
if(isDimHidden(j)) {
continue;
}
int i = dimOrder[j];
double w = scales[i].getScaled(data.doubleValue(i));
w = isDimInverted(i) ? w : 1 - w;
v[o++] = w * StyleLibrary.SCALE;
}
return v;
}
@Override
public double[] fastProjectDataToRenderSpace(double[] data) {
double[] v = new double[visDims];
for(int j = 0, o = 0; j < scales.length; j++) {
if(isDimHidden(j)) {
continue;
}
int i = dimOrder[j];
double w = scales[i].getScaled(data[i]);
w = isDimInverted(i) ? w : 1 - w;
v[o++] = w * StyleLibrary.SCALE;
}
return v;
}
@Override
public double fastProjectRenderToDataSpace(double v, int projdim) {
int truedim = dimOrder[projdim];
v /= StyleLibrary.SCALE;
v = isDimInverted(truedim) ? v : 1 - v;
return scales[truedim].getUnscaled(v);
}
@Override
public double fastProjectDataToRenderSpace(double value, int dim) {
double temp = scales[dimOrder[dim]].getScaled(value);
temp *= StyleLibrary.SCALE;
return isAxisInverted(dimOrder[dim]) ? 1 - temp : temp;
}
@Override
public int getAxisForDim(int truedim) {
for(int i = 0; i < dimOrder.length; i++) {
if(dimOrder[i] == truedim) {
return i;
}
}
return -1;
}
@Override
public int getInputDimensionality() {
return scales.length;
}
@Override
public String getMenuName() {
return "Parallel Coordinates";
}
@Override
public Projector getProjector() {
return p;
}
} package-info.java 0000775 0000000 0000000 00000001714 12657057427 0035551 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projections /**
*
Visualization projections
*/
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.lmu.ifi.dbs.elki.visualization.projections; elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projector/ 0000775 0000000 0000000 00000000000 12657057427 0032103 5 ustar 00root root 0000000 0000000 HistogramFactory.java 0000664 0000000 0000000 00000010146 12657057427 0036156 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projector package de.lmu.ifi.dbs.elki.visualization.projector;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.data.type.TypeUtil;
import de.lmu.ifi.dbs.elki.database.relation.Relation;
import de.lmu.ifi.dbs.elki.database.relation.RelationUtil;
import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.FilteredIter;
import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.Hierarchy;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.CommonConstraints;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.IntParameter;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTree;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
/**
* Produce one-dimensional projections.
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.has HistogramProjector
*/
public class HistogramFactory implements ProjectorFactory {
/**
* Maximum dimensionality.
*/
private int maxdim = ScatterPlotFactory.MAX_DIMENSIONS_DEFAULT;
/**
* Constructor.
*
* @param maxdim Maximum dimensionality
*/
public HistogramFactory(int maxdim) {
super();
this.maxdim = maxdim;
}
@Override
public void processNewResult(VisualizerContext context, Object start) {
Hierarchy.Iter> it1 = VisualizationTree.filterResults(context, start, Relation.class);
candidate: for(; it1.valid(); it1.advance()) {
Relation> rel = it1.get();
if(!TypeUtil.NUMBER_VECTOR_FIELD.isAssignableFromType(rel.getDataTypeInformation())) {
continue;
}
// Do not enable nested relations by default:
Hierarchy.Iter> it2 = new FilteredIter<>(context.getHierarchy().iterAncestors(rel), Relation.class);
for(; it2.valid(); it2.advance()) {
// Parent relation
final Relation> rel2 = (Relation>) it2.get();
if(TypeUtil.SPATIAL_OBJECT.isAssignableFromType(rel2.getDataTypeInformation())) {
continue candidate;
}
// TODO: add Actions instead.
}
@SuppressWarnings("unchecked")
Relation vrel = (Relation) rel;
final int dim = RelationUtil.dimensionality(vrel);
HistogramProjector proj = new HistogramProjector<>(vrel, Math.min(dim, maxdim));
context.addVis(vrel, proj);
}
}
/**
* Parameterization class.
*
* @author Erich Schubert
*
* @apiviz.exclude
*/
public static class Parameterizer extends AbstractParameterizer {
/**
* Stores the maximum number of dimensions to show.
*/
private int maxdim = ScatterPlotFactory.MAX_DIMENSIONS_DEFAULT;
@Override
protected void makeOptions(Parameterization config) {
super.makeOptions(config);
IntParameter maxdimP = new IntParameter(ScatterPlotFactory.Parameterizer.MAXDIM_ID, ScatterPlotFactory.MAX_DIMENSIONS_DEFAULT);
maxdimP.addConstraint(CommonConstraints.GREATER_EQUAL_ZERO_INT);
if(config.grab(maxdimP)) {
maxdim = maxdimP.intValue();
}
}
@Override
protected HistogramFactory makeInstance() {
return new HistogramFactory(maxdim);
}
}
} HistogramProjector.java 0000664 0000000 0000000 00000007560 12657057427 0036524 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projector package de.lmu.ifi.dbs.elki.visualization.projector;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.database.relation.Relation;
import de.lmu.ifi.dbs.elki.database.relation.RelationUtil;
import de.lmu.ifi.dbs.elki.result.ResultUtil;
import de.lmu.ifi.dbs.elki.result.ScalesResult;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.gui.overview.PlotItem;
import de.lmu.ifi.dbs.elki.visualization.projections.Projection1D;
import de.lmu.ifi.dbs.elki.visualization.projections.Simple1D;
import de.lmu.ifi.dbs.elki.visualization.visualizers.visunproj.LabelVisualization;
/**
* ScatterPlotProjector is responsible for producing a set of scatterplot
* visualizations.
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.uses ScalesResult
* @apiviz.uses Projection1D
*
* @param Vector type
*/
public class HistogramProjector implements Projector {
/**
* Relation we project.
*/
Relation rel;
/**
* Database dimensionality.
*/
int dmax;
/**
* Constructor.
*
* @param rel Relation
* @param maxdim Maximum dimension to use
*/
public HistogramProjector(Relation rel, int maxdim) {
super();
this.rel = rel;
this.dmax = maxdim;
assert(maxdim <= RelationUtil.dimensionality(rel)) : "Requested dimensionality larger than data dimensionality?!?";
}
@Override
public Collection arrange(VisualizerContext context) {
List layout = new ArrayList<>(1 + dmax);
List tasks = context.getVisTasks(this);
if(tasks.size() > 0) {
final double xoff = (dmax > 1) ? .1 : 0.;
final double hheight = .5;
final double lheight = .1;
PlotItem master = new PlotItem(dmax + xoff, hheight + lheight, null);
ScalesResult scales = ResultUtil.getScalesResult(rel);
for(int d1 = 0; d1 < dmax; d1++) {
Projection1D proj = new Simple1D(this, scales.getScales(), d1);
final PlotItem it = new PlotItem(d1 + xoff, lheight, 1., hheight, proj);
it.tasks = tasks;
master.subitems.add(it);
}
layout.add(master);
// Add labels
for(int d1 = 0; d1 < dmax; d1++) {
PlotItem it = new PlotItem(d1 + xoff, 0, 1., lheight, null);
LabelVisualization lbl = new LabelVisualization(RelationUtil.getColumnLabel(rel, d1));
final VisualizationTask task = new VisualizationTask("", context, null, null, lbl);
task.reqheight = lheight;
task.reqwidth = 1;
task.addFlags(VisualizationTask.FLAG_NO_DETAIL);
it.tasks.add(task);
master.subitems.add(it);
}
}
return layout;
}
@Override
public String getMenuName() {
return "Axis plot";
}
/**
* Get the relation we project.
*
* @return Relation
*/
public Relation getRelation() {
return rel;
}
} OPTICSProjector.java 0000664 0000000 0000000 00000005260 12657057427 0035563 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projector package de.lmu.ifi.dbs.elki.visualization.projector;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import de.lmu.ifi.dbs.elki.algorithm.clustering.optics.ClusterOrder;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.gui.overview.PlotItem;
import de.lmu.ifi.dbs.elki.visualization.opticsplot.OPTICSPlot;
import de.lmu.ifi.dbs.elki.visualization.projections.OPTICSProjection;
/**
* Projection for OPTICS plots.
*
* @author Erich Schubert
* @since 0.4.0
*/
public class OPTICSProjector implements Projector {
/**
* Cluster order result
*/
private ClusterOrder clusterOrder;
/**
* OPTICS plot image
*/
private OPTICSPlot plot = null;
/**
* Constructor.
*
* @param co Cluster order
*/
public OPTICSProjector(ClusterOrder co) {
super();
this.clusterOrder = co;
}
@Override
public String getMenuName() {
return "OPTICS Plot Projection";
}
@Override
public Collection arrange(VisualizerContext context) {
List col = new ArrayList<>(1);
List tasks = context.getVisTasks(this);
if(tasks.size() > 0) {
final PlotItem it = new PlotItem(4., 1., new OPTICSProjection(this));
it.tasks = tasks;
col.add(it);
}
return col;
}
/**
* Get the cluster order
*
* @return the cluster order
*/
public ClusterOrder getResult() {
return clusterOrder;
}
/**
* Get or produce the actual OPTICS plot.
*
* @param context Context to use
* @return Plot
*/
public OPTICSPlot getOPTICSPlot(VisualizerContext context) {
if(plot == null) {
plot = OPTICSPlot.plotForClusterOrder(clusterOrder, context);
}
return plot;
}
} OPTICSProjectorFactory.java 0000664 0000000 0000000 00000003431 12657057427 0037111 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projector package de.lmu.ifi.dbs.elki.visualization.projector;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.algorithm.clustering.optics.ClusterOrder;
import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.Hierarchy;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTree;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
/**
* Produce OPTICS plot projections
*
* @author Erich Schubert
* @since 0.2
*
* @apiviz.has OPTICSProjector
*/
public class OPTICSProjectorFactory implements ProjectorFactory {
/**
* Constructor.
*/
public OPTICSProjectorFactory() {
super();
}
@Override
public void processNewResult(VisualizerContext context, Object start) {
Hierarchy.Iter it1 = VisualizationTree.filterResults(context, start, ClusterOrder.class);
for(; it1.valid(); it1.advance()) {
final ClusterOrder or = it1.get();
context.addVis(or, new OPTICSProjector(or));
}
}
}
ParallelPlotFactory.java 0000664 0000000 0000000 00000006757 12657057427 0036631 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projector package de.lmu.ifi.dbs.elki.visualization.projector;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable;
import de.lmu.ifi.dbs.elki.data.type.TypeUtil;
import de.lmu.ifi.dbs.elki.data.uncertain.UncertainObject;
import de.lmu.ifi.dbs.elki.database.relation.Relation;
import de.lmu.ifi.dbs.elki.database.relation.RelationUtil;
import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.FilteredIter;
import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.Hierarchy;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTree;
/**
* Produce parallel axes projections.
*
* @author Robert Rödler
* @since 0.5.0
*
* @apiviz.has ParallelPlotProjector
*/
public class ParallelPlotFactory implements ProjectorFactory {
/**
* Constructor.
*/
public ParallelPlotFactory() {
super();
}
@Override
public void processNewResult(VisualizerContext context, Object start) {
Hierarchy.Iter> it = VisualizationTree.filterResults(context, start, Relation.class);
candidate: for(; it.valid(); it.advance()) {
Relation> rel = it.get();
// TODO: multi-relational parallel plots?
final int dim = dimensionality(rel);
if(dim <= 1) {
continue;
}
// Do not enable nested relations by default:
Hierarchy.Iter> it2 = new FilteredIter<>(context.getHierarchy().iterAncestors(rel), Relation.class);
for(; it2.valid(); it2.advance()) {
// Parent relation
final Relation> rel2 = (Relation>) it2.get();
final int odim = dimensionality(rel2);
if(odim == dim) {
// TODO: add Actions instead?
continue candidate;
}
}
@SuppressWarnings("unchecked")
Relation vrel = (Relation) rel;
ParallelPlotProjector proj = new ParallelPlotProjector<>(vrel);
context.addVis(vrel, proj);
}
}
private int dimensionality(Relation> rel) {
if(TypeUtil.NUMBER_VECTOR_FIELD.isAssignableFromType(rel.getDataTypeInformation())) {
@SuppressWarnings("unchecked")
Relation vrel = (Relation) rel;
return RelationUtil.dimensionality(vrel);
}
if(TypeUtil.UNCERTAIN_OBJECT_FIELD.isAssignableFromType(rel.getDataTypeInformation())) {
@SuppressWarnings("unchecked")
Relation vrel = (Relation) rel;
return RelationUtil.dimensionality(vrel);
}
// TODO: allow other spatial objects of fixed dimensionality!
return 0;
}
} ParallelPlotProjector.java 0000664 0000000 0000000 00000005543 12657057427 0037161 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projector package de.lmu.ifi.dbs.elki.visualization.projector;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable;
import de.lmu.ifi.dbs.elki.database.relation.Relation;
import de.lmu.ifi.dbs.elki.math.MathUtil;
import de.lmu.ifi.dbs.elki.result.ResultUtil;
import de.lmu.ifi.dbs.elki.result.ScalesResult;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.gui.overview.PlotItem;
import de.lmu.ifi.dbs.elki.visualization.projections.ProjectionParallel;
import de.lmu.ifi.dbs.elki.visualization.projections.SimpleParallel;
/**
* ParallelPlotProjector is responsible for producing a parallel axes
* visualization.
*
* @author Robert Rödler
* @since 0.5.0
*
* @param Vector type
*/
// TODO: support categorical features, and multiple relations too
public class ParallelPlotProjector implements Projector {
/**
* Relation we project.
*/
Relation rel;
/**
* Constructor.
*
* @param rel Relation
*/
public ParallelPlotProjector(Relation rel) {
super();
this.rel = rel;
}
@Override
public Collection arrange(VisualizerContext context) {
List col = new ArrayList<>(1);
List tasks = context.getVisTasks(this);
if(tasks.size() > 0) {
ScalesResult scales = ResultUtil.getScalesResult(rel);
ProjectionParallel proj = new SimpleParallel(this, scales.getScales());
final double width = Math.max(.5, Math.ceil(MathUtil.log2(scales.getScales().length - 1)));
final PlotItem it = new PlotItem(width, 1., proj);
it.tasks = tasks;
col.add(it);
}
return col;
}
@Override
public String getMenuName() {
return "Parallelplot";
}
/**
* The relation we project.
*
* @return Relation
*/
public Relation getRelation() {
return rel;
}
} Projector.java 0000664 0000000 0000000 00000003004 12657057427 0034633 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projector package de.lmu.ifi.dbs.elki.visualization.projector;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.Collection;
import de.lmu.ifi.dbs.elki.visualization.VisualizationItem;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.gui.overview.PlotItem;
/**
* A projector is responsible for adding projections to the visualization.
*
* @author Erich Schubert
* @since 0.4.0
*/
public interface Projector extends VisualizationItem {
/**
* Produce an arrangement of projections.
*
* @param context Visualization context
* @return Arrangement.
*/
public Collection arrange(VisualizerContext context);
} ProjectorFactory.java 0000664 0000000 0000000 00000003067 12657057427 0036174 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projector package de.lmu.ifi.dbs.elki.visualization.projector;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.visualization.VisualizationProcessor;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
/**
* A projector is responsible for adding projections to the visualization by
* detecting appropriate relations in the database.
*
* @author Erich Schubert
* @since 0.2
*
* @apiviz.has Projector
*/
public interface ProjectorFactory extends VisualizationProcessor {
/**
* Add projections for the given result (tree) to the result tree.
* @param context Visualization context
* @param start Result to process
*/
@Override
public void processNewResult(VisualizerContext context, Object start);
} ScatterPlotFactory.java 0000664 0000000 0000000 00000012276 12657057427 0036473 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projector package de.lmu.ifi.dbs.elki.visualization.projector;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable;
import de.lmu.ifi.dbs.elki.data.type.TypeUtil;
import de.lmu.ifi.dbs.elki.data.uncertain.UncertainObject;
import de.lmu.ifi.dbs.elki.database.relation.Relation;
import de.lmu.ifi.dbs.elki.database.relation.RelationUtil;
import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.FilteredIter;
import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.Hierarchy;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.CommonConstraints;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.IntParameter;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTree;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
/**
* Produce scatterplot projections.
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.has ScatterPlotProjector
*/
public class ScatterPlotFactory implements ProjectorFactory {
/**
* Maximum number of dimensions to visualize.
*
* FIXME: add scrolling function for higher dimensionality!
*/
public static final int MAX_DIMENSIONS_DEFAULT = 10;
/**
* Stores the maximum number of dimensions to show.
*/
private int maxdim = MAX_DIMENSIONS_DEFAULT;
/**
* Constructor.
*
* @param maxdim Maximum number of dimensions to show.
*/
public ScatterPlotFactory(int maxdim) {
super();
this.maxdim = maxdim;
}
@Override
public void processNewResult(VisualizerContext context, Object start) {
Hierarchy.Iter> it = VisualizationTree.filterResults(context, start, Relation.class);
candidate: for(; it.valid(); it.advance()) {
Relation> rel = it.get();
final int dim = dimensionality(rel);
if(dim < 1) {
continue;
}
// Do not enable nested relations by default:
Hierarchy.Iter> it2 = new FilteredIter<>(context.getHierarchy().iterAncestors(rel), Relation.class);
for(; it2.valid(); it2.advance()) {
// Parent relation
final Relation> rel2 = (Relation>) it2.get();
final int odim = dimensionality(rel2);
if(odim == dim) {
// TODO: add Actions instead?
continue candidate;
}
}
@SuppressWarnings("unchecked")
Relation vrel = (Relation) rel;
ScatterPlotProjector proj = new ScatterPlotProjector<>(vrel, Math.min(maxdim, dim));
context.addVis(vrel, proj);
}
}
private int dimensionality(Relation> rel) {
if(TypeUtil.NUMBER_VECTOR_FIELD.isAssignableFromType(rel.getDataTypeInformation())) {
@SuppressWarnings("unchecked")
Relation vrel = (Relation) rel;
return RelationUtil.dimensionality(vrel);
}
if(TypeUtil.UNCERTAIN_OBJECT_FIELD.isAssignableFromType(rel.getDataTypeInformation())) {
@SuppressWarnings("unchecked")
Relation vrel = (Relation) rel;
return RelationUtil.dimensionality(vrel);
}
// TODO: allow other spatial objects of fixed dimensionality!
return 0;
}
/**
* Parameterization class.
*
* @author Erich Schubert
*
* @apiviz.exclude
*/
public static class Parameterizer extends AbstractParameterizer {
/**
* Parameter for the maximum number of dimensions.
*
*
* Code: -vis.maxdim
*
*/
public static final OptionID MAXDIM_ID = new OptionID("vis.maxdim", "Maximum number of dimensions to display.");
/**
* Stores the maximum number of dimensions to show.
*/
private int maxdim = MAX_DIMENSIONS_DEFAULT;
@Override
protected void makeOptions(Parameterization config) {
super.makeOptions(config);
IntParameter maxdimP = new IntParameter(MAXDIM_ID, MAX_DIMENSIONS_DEFAULT);
maxdimP.addConstraint(CommonConstraints.GREATER_EQUAL_ZERO_INT);
if(config.grab(maxdimP)) {
maxdim = maxdimP.intValue();
}
}
@Override
protected ScatterPlotFactory makeInstance() {
return new ScatterPlotFactory(maxdim);
}
}
} ScatterPlotProjector.java 0000664 0000000 0000000 00000014522 12657057427 0037027 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projector package de.lmu.ifi.dbs.elki.visualization.projector;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable;
import de.lmu.ifi.dbs.elki.database.relation.Relation;
import de.lmu.ifi.dbs.elki.database.relation.RelationUtil;
import de.lmu.ifi.dbs.elki.math.linearalgebra.AffineTransformation;
import de.lmu.ifi.dbs.elki.result.ResultUtil;
import de.lmu.ifi.dbs.elki.result.ScalesResult;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.gui.overview.PlotItem;
import de.lmu.ifi.dbs.elki.visualization.projections.AffineProjection;
import de.lmu.ifi.dbs.elki.visualization.projections.Projection2D;
import de.lmu.ifi.dbs.elki.visualization.projections.Simple2D;
import de.lmu.ifi.dbs.elki.visualization.visualizers.visunproj.LabelVisualization;
/**
* ScatterPlotProjector is responsible for producing a set of scatterplot
* visualizations.
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.uses ScalesResult
* @apiviz.uses Projection2D
*
* @param Vector type
*/
public class ScatterPlotProjector implements Projector {
/**
* Relation we project.
*/
Relation rel;
/**
* Database dimensionality.
*/
int dmax;
/**
* Constructor.
*
* @param rel Relation
* @param maxdim Maximum dimension to use
*/
public ScatterPlotProjector(Relation rel, int maxdim) {
super();
this.rel = rel;
this.dmax = maxdim;
assert(maxdim <= RelationUtil.dimensionality(rel)) : "Requested dimensionality larger than data dimensionality?!?";
}
@Override
public Collection arrange(VisualizerContext context) {
List layout = new ArrayList<>(1);
List tasks = context.getVisTasks(this);
if(tasks.size() > 0) {
ScalesResult scales = ResultUtil.getScalesResult(rel);
final PlotItem master;
if(dmax == 2) {
// In 2d, make the plot twice as big.
master = new PlotItem(2 + .1, 2 + .1, null);
{
Projection2D proj = new Simple2D(this, scales.getScales(), 0, 1);
PlotItem it = new PlotItem(.1, 0, 2., 2., proj);
it.tasks = tasks;
master.subitems.add(it);
}
// Label at bottom
{
PlotItem it = new PlotItem(.1, 2., 2., .1, null);
final VisualizationTask task = new VisualizationTask("", context, null, null, new LabelVisualization(RelationUtil.getColumnLabel(rel, 0)));
task.reqheight = .1;
task.reqwidth = 2.;
task.addFlags(VisualizationTask.FLAG_NO_DETAIL);
it.tasks.add(task);
master.subitems.add(it);
}
// Label on left
{
PlotItem it = new PlotItem(0, 0, .1, 2, null);
final VisualizationTask task = new VisualizationTask("", context, null, null, new LabelVisualization(RelationUtil.getColumnLabel(rel, 1), true));
task.reqheight = 2.;
task.reqwidth = .1;
task.addFlags(VisualizationTask.FLAG_NO_DETAIL);
it.tasks.add(task);
master.subitems.add(it);
}
}
else {
final double sizeh = Math.ceil((dmax - 1) / 2.0);
master = new PlotItem(sizeh * 2. + .1, dmax - 1 + .1, null);
for(int d1 = 0; d1 < dmax - 1; d1++) {
for(int d2 = d1 + 1; d2 < dmax; d2++) {
Projection2D proj = new Simple2D(this, scales.getScales(), d1, d2);
PlotItem it = new PlotItem(d1 + .1, d2 - 1, 1., 1., proj);
it.tasks = tasks;
master.subitems.add(it);
}
}
if(dmax >= 3) {
AffineTransformation p = AffineProjection.axisProjection(RelationUtil.dimensionality(rel), 1, 2);
p.addRotation(0, 2, Math.PI / 180 * -10.);
p.addRotation(1, 2, Math.PI / 180 * 15.);
// Wanna try 4d? go ahead:
// p.addRotation(0, 3, Math.PI / 180 * -20.);
// p.addRotation(1, 3, Math.PI / 180 * 30.);
Projection2D proj = new AffineProjection(this, scales.getScales(), p);
PlotItem it = new PlotItem(sizeh + .1, 0, sizeh, sizeh, proj);
it.tasks = tasks;
master.subitems.add(it);
}
// Labels at bottom
for(int d1 = 0; d1 < dmax - 1; d1++) {
PlotItem it = new PlotItem(d1 + .1, dmax - 1, 1., .1, null);
final VisualizationTask task = new VisualizationTask("", context, null, null, new LabelVisualization(RelationUtil.getColumnLabel(rel, d1)));
task.reqheight = .1;
task.reqwidth = 1;
task.addFlags(VisualizationTask.FLAG_NO_DETAIL);
it.tasks.add(task);
master.subitems.add(it);
}
// Labels on left
for(int d2 = 1; d2 < dmax; d2++) {
PlotItem it = new PlotItem(0, d2 - 1, .1, 1, null);
final VisualizationTask task = new VisualizationTask("", context, null, null, new LabelVisualization(RelationUtil.getColumnLabel(rel, d2), true));
task.reqheight = 1;
task.reqwidth = .1;
task.addFlags(VisualizationTask.FLAG_NO_DETAIL);
it.tasks.add(task);
master.subitems.add(it);
}
}
layout.add(master);
}
return layout;
}
@Override
public String getMenuName() {
return "Scatterplot";
}
/**
* The relation we project.
*
* @return Relation
*/
public Relation getRelation() {
return rel;
}
} package-info.java 0000775 0000000 0000000 00000002003 12657057427 0035211 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/projector /**
*
Projectors are responsible for finding appropriate projections for data relations.
*/
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.lmu.ifi.dbs.elki.visualization.projector; elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/savedialog/ 0000775 0000000 0000000 00000000000 12657057427 0032212 5 ustar 00root root 0000000 0000000 SVGSaveDialog.java 0000664 0000000 0000000 00000017112 12657057427 0035376 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/savedialog package de.lmu.ifi.dbs.elki.visualization.savedialog;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2016
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.awt.Component;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactoryConfigurationError;
import org.apache.batik.ext.awt.image.spi.ImageTagRegistry;
import org.apache.batik.ext.awt.image.spi.ImageWriterRegistry;
import org.apache.batik.transcoder.TranscoderException;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.utilities.FileUtil;
import de.lmu.ifi.dbs.elki.visualization.batikutil.BatikUtil;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGPlot;
/**
* A save dialog to save/export a SVG image to a file.
*
* Supported formats:
*
*
SVG
*
PNG (with width and height options)
*
JPEG (with width and height options, and if an ImageWrite is available)
*
*
PDF (if FOP transcoders are available)
*
PS (if FOP transcoders are available)
*
EPS (if FOP transcoders are available)
*
*
* @author Simon Mittermüller
* @since 0.2
*
* @apiviz.composedOf SaveOptionsPanel
*/
public class SVGSaveDialog {
/** The default title. "Save as ...". */
public static final String DEFAULT_TITLE = "Save as ...";
/** Static logger reference */
private static final Logging LOG = Logging.getLogger(SVGSaveDialog.class);
/** Automagic file format */
final static String AUTOMAGIC_FORMAT = "automatic";
/** Supported file format (extensions) */
final static String[] FORMATS;
/** Visible file formats */
final static String[] VISIBLE_FORMATS;
static {
ArrayList fmt = new ArrayList<>();
fmt.add(AUTOMAGIC_FORMAT);
fmt.add("svg");
// Check that the image writers are available:
ImageWriterRegistry reg = ImageWriterRegistry.getInstance();
// Detect broken Batik unable to use inlined base64 images:
ImageTagRegistry tagreg = ImageTagRegistry.getRegistry();
// These will only work if we can decode pngs (thumbnails in overview)!
if(tagreg.getRegisteredMimeTypes().contains("image/png")) {
if(reg.getWriterFor("image/png") != null) {
fmt.add("png");
}
if(reg.getWriterFor("image/jpeg") != null) {
fmt.add("jpeg");
}
}
// FOP installed?
if(BatikUtil.hasFOPInstalled()) {
fmt.add("pdf");
fmt.add("ps");
fmt.add("eps");
}
FORMATS = fmt.toArray(new String[fmt.size()]);
fmt.remove(0);
VISIBLE_FORMATS = fmt.toArray(new String[fmt.size()]);
}
/**
* Show a "Save as" dialog.
*
* @param plot The plot to be exported.
* @param width The width of the exported image (when export to JPEG/PNG).
* @param height The height of the exported image (when export to JPEG/PNG).
* @return Result from {@link JFileChooser#showSaveDialog}
*/
public static int showSaveDialog(SVGPlot plot, int width, int height) {
double quality = 1.0;
int ret = -1;
JFileChooser fc = new JFileChooser(new File("."));
fc.setDialogTitle(DEFAULT_TITLE);
// fc.setFileFilter(new ImageFilter());
SaveOptionsPanel optionsPanel = new SaveOptionsPanel(fc, width, height);
fc.setAccessory(optionsPanel);
ret = fc.showSaveDialog(null);
fc.setDialogTitle("Saving... Please wait.");
if(ret == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
String format = optionsPanel.getSelectedFormat();
if(format == null || AUTOMAGIC_FORMAT.equals(format)) {
format = guessFormat(file.getName());
}
try {
if(format == null) {
showError(fc, "Error saving image.", "File format not recognized.");
}
else if("jpeg".equals(format) || "jpg".equals(format)) {
quality = optionsPanel.getJPEGQuality();
plot.saveAsJPEG(file, width, height, quality);
}
else if("png".equals(format)) {
plot.saveAsPNG(file, width, height);
}
else if("ps".equals(format)) {
plot.saveAsPS(file);
}
else if("eps".equals(format)) {
plot.saveAsEPS(file);
}
else if("pdf".equals(format)) {
plot.saveAsPDF(file);
}
else if("svg".equals(format)) {
plot.saveAsSVG(file);
}
else {
showError(fc, "Error saving image.", "Unsupported format: " + format);
}
}
catch(java.lang.IncompatibleClassChangeError e) {
showError(fc, "Error saving image.", "It seems that your Java version is incompatible with this version of Batik and Jpeg writing. Sorry.");
}
catch(ClassNotFoundException e) {
showError(fc, "Error saving image.", "A class was not found when saving this image. Maybe installing Apache FOP will help (for PDF, PS and EPS output).\n" + e.toString());
}
catch(IOException e) {
LOG.exception(e);
showError(fc, "Error saving image.", e.toString());
}
catch(TranscoderException e) {
LOG.exception(e);
showError(fc, "Error saving image.", e.toString());
}
catch(TransformerFactoryConfigurationError e) {
LOG.exception(e);
showError(fc, "Error saving image.", e.toString());
}
catch(TransformerException e) {
LOG.exception(e);
showError(fc, "Error saving image.", e.toString());
}
catch(Exception e) {
LOG.exception(e);
showError(fc, "Error saving image.", e.toString());
}
}
else if(ret == JFileChooser.ERROR_OPTION) {
showError(fc, "Error in file dialog.", "Unknown Error.");
}
else if(ret == JFileChooser.CANCEL_OPTION) {
// do nothing - except return result
}
return ret;
}
/**
* Guess a supported format from the file name. For "auto" format handling.
*
* @param name File name
* @return format or "null"
*/
public static String guessFormat(String name) {
String ext = FileUtil.getFilenameExtension(name);
for(String format : FORMATS) {
if(format.equals(ext)) {
return ext;
}
}
return null;
}
/**
* @return the formats
*/
public static String[] getFormats() {
return FORMATS;
}
/**
* @return the visibleformats
*/
public static String[] getVisibleFormats() {
return VISIBLE_FORMATS;
}
/**
* Helper method to show a error message as "popup". Calls
* {@link JOptionPane#showMessageDialog(java.awt.Component, Object)}.
*
* @param parent The parent component for the popup.
* @param msg The message to be displayed.
*/
private static void showError(Component parent, String title, String msg) {
JOptionPane.showMessageDialog(parent, msg, title, JOptionPane.ERROR_MESSAGE);
}
}
SaveOptionsPanel.java 0000664 0000000 0000000 00000022616 12657057427 0036237 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/savedialog package de.lmu.ifi.dbs.elki.visualization.savedialog;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
* A component (JPanel) which can be displayed in the save dialog to show
* additional options when saving as JPEG or PNG.
*
* @author Simon Mittermüller
* @since 0.2
*/
public class SaveOptionsPanel extends JPanel {
// TODO: externalize strings
private static final String STR_IMAGE_SIZE = "Size options:";
private static final String STR_JPEG_QUALITY = "Quality:";
private static final String STR_IMAGE_HEIGHT = "Height:";
private static final String STR_IMAGE_WIDTH = "Width:";
private static final String STR_CHOOSE_FORMAT = "Choose format:";
private static final String STR_RESET_IMAGE_SIZE = "Reset image size";
private static final String STR_LOCK_ASPECT_RATIO = "Lock aspect ratio";
/**
* Serial version.
*/
private static final long serialVersionUID = 1L;
/** The fileChooser on which this panel is installed. */
private JFileChooser fc;
/**
* The width of the exported image (if exported to JPEG or PNG). Default is
* 1024.
*/
protected int width = 1024;
/**
* The height of the exported image (if exported to JPEG or PNG). Default is
* 768.
*/
protected int height = 768;
/** Ratio for easier size adjustment */
double ratio = 16.0 / 10.0;
/** Main panel */
private JPanel mainPanel;
/** Shows quality info when saving as JPEG. */
private JPanel qualPanel;
/** If saving as JPEG/PNG show width/height infos here. */
private JPanel sizePanel;
protected JSpinner spinnerWidth;
protected JSpinner spinnerHeight;
protected JSpinner spinnerQual;
protected SpinnerNumberModel modelWidth;
protected SpinnerNumberModel modelHeight;
protected SpinnerNumberModel modelQuality;
protected JCheckBox aspectRatioLock;
protected JButton resetSizeButton;
protected JComboBox formatSelector;
// Not particularly useful for most - hide it for now.
private final boolean hasResetButton = false;
/**
* Construct a new Save Options Panel.
*
* @param fc File chooser to display in
* @param w Default image width
* @param h Default image height
*/
public SaveOptionsPanel(JFileChooser fc, int w, int h) {
this.width = w;
this.height = h;
this.ratio = (double) w / (double) h;
this.fc = fc;
mainPanel = new JPanel();
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS));
sizePanel = new JPanel();
sizePanel.setLayout(new BoxLayout(sizePanel, BoxLayout.Y_AXIS));
sizePanel.setBorder(BorderFactory.createTitledBorder(STR_IMAGE_SIZE));
// *** Format panel
mainPanel.add(new JLabel(STR_CHOOSE_FORMAT));
formatSelector = new JComboBox<>(SVGSaveDialog.getVisibleFormats());
formatSelector.setSelectedIndex(0);
formatSelector.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if(e.getItem() != null) {
String format = (String) formatSelector.getSelectedItem();
setFormat(format);
}
}
});
mainPanel.add(formatSelector);
// *** Size panel
JPanel widthPanel = new JPanel();
JPanel heightPanel = new JPanel();
widthPanel.add(new JLabel(STR_IMAGE_WIDTH));
heightPanel.add(new JLabel(STR_IMAGE_HEIGHT));
// size models
modelWidth = new SpinnerNumberModel(width, 0, 100000, 1);
modelHeight = new SpinnerNumberModel(height, 0, 100000, 1);
// size spinners
spinnerWidth = new JSpinner(modelWidth);
spinnerWidth.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
if(aspectRatioLock.isSelected()) {
int val = modelWidth.getNumber().intValue();
spinnerHeight.setValue(new Integer((int) Math.round(val / ratio)));
}
}
});
widthPanel.add(spinnerWidth);
spinnerHeight = new JSpinner(modelHeight);
spinnerHeight.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
if(aspectRatioLock.isSelected()) {
int val = modelHeight.getNumber().intValue();
spinnerWidth.setValue(new Integer((int) Math.round(val * ratio)));
}
}
});
heightPanel.add(spinnerHeight);
// add subpanels
sizePanel.add(widthPanel);
sizePanel.add(heightPanel);
// aspect lock
aspectRatioLock = new JCheckBox(STR_LOCK_ASPECT_RATIO);
aspectRatioLock.setSelected(true);
// aspectRatioLock.addActionListener(x);
sizePanel.add(aspectRatioLock);
// reset size button
if(hasResetButton) {
resetSizeButton = new JButton(STR_RESET_IMAGE_SIZE);
resetSizeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
modelWidth.setValue(Integer.valueOf(width));
modelHeight.setValue(Integer.valueOf(height));
aspectRatioLock.setSelected(true);
}
});
sizePanel.add(resetSizeButton);
}
mainPanel.add(sizePanel);
// Quality settings panel
qualPanel = new JPanel();
// quality settings will not be visible by default (JPEG only)
qualPanel.setVisible(false);
qualPanel.setLayout(new BoxLayout(qualPanel, BoxLayout.Y_AXIS));
qualPanel.setBorder(BorderFactory.createTitledBorder(STR_JPEG_QUALITY));
modelQuality = new SpinnerNumberModel(0.7, 0.1, 1.0, 0.1);
spinnerQual = new JSpinner(modelQuality);
// spinnerQual.addChangeListener(x);
qualPanel.add(spinnerQual);
mainPanel.add(qualPanel);
add(mainPanel);
// setup a listener to react to file name changes
this.fc.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent e) {
if(e.getPropertyName().equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) {
File file = (File) e.getNewValue();
if(file != null && file.getName() != null) {
String format = SVGSaveDialog.guessFormat(file.getName());
if(format != null) {
setFormat(format);
}
}
}
}
});
}
protected void setFormat(String format) {
String[] formats = SVGSaveDialog.getVisibleFormats();
int index = -1;
for(int i = 0; i < formats.length; i++) {
if(formats[i].equals(format)) {
index = i;
break;
}
}
if(index != formatSelector.getSelectedIndex() && index >= 0) {
formatSelector.setSelectedIndex(index);
}
if(format.equals("jpeg") || format.equals("jpg")) {
sizePanel.setVisible(true);
qualPanel.setVisible(true);
}
else if(format.equals("png")) {
sizePanel.setVisible(true);
qualPanel.setVisible(false);
}
else if(format.equals("pdf")) {
sizePanel.setVisible(false);
qualPanel.setVisible(false);
mainPanel.validate();
}
else if(format.equals("ps")) {
sizePanel.setVisible(false);
qualPanel.setVisible(false);
mainPanel.validate();
}
else if(format.equals("eps")) {
sizePanel.setVisible(false);
qualPanel.setVisible(false);
mainPanel.validate();
}
else if(format.equals("svg")) {
sizePanel.setVisible(false);
qualPanel.setVisible(false);
mainPanel.validate();
}
else {
// TODO: what to do on unknown formats?
// LoggingUtil.warning("Unrecognized file extension seen: " + format);
}
}
/**
* Return the selected file format.
*
* @return file format identification
*/
public String getSelectedFormat() {
String format = (String) formatSelector.getSelectedItem();
return format;
}
/**
* Returns the quality value in the quality field.
*
* It is ensured that return value is in the range of [0:1]
*
* @return Quality value for JPEG.
*/
public double getJPEGQuality() {
double qual =modelQuality.getNumber().doubleValue();
if(qual > 1.0) {
qual = 1.0;
}
if(qual < 0) {
qual = 0.0;
}
return qual;
}
} package-info.java 0000664 0000000 0000000 00000001720 12657057427 0035322 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/savedialog /**
*
Save dialog for SVG plots.
*
*/
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.lmu.ifi.dbs.elki.visualization.savedialog; elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/ 0000775 0000000 0000000 00000000000 12657057427 0031234 5 ustar 00root root 0000000 0000000 ClassStylingPolicy.java 0000664 0000000 0000000 00000003751 12657057427 0035625 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style package de.lmu.ifi.dbs.elki.visualization.style;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
/**
* Styling policy that is based on classes, for example clusters or
* labels. This allows for certain optimizations such as marker reuse, and thus
* is preferred when possible.
*
* @author Erich Schubert
* @since 0.4.0
*/
public interface ClassStylingPolicy extends StylingPolicy {
/**
* Get the style number for a particular object
*
* @param id Object ID
* @return Style number
*/
int getStyleForDBID(DBIDRef id);
/**
* Get the minimum style in use.
*
* @return Style number
*/
int getMinStyle();
/**
* Get the maximum style in use.
*
* @return Style number
*/
int getMaxStyle();
/**
* Iterate over all objects from a given class.
*
* @param cnum Class number
* @return Iterator over object IDs
*/
DBIDIter iterateClass(int cnum);
/**
* Get the number of elements in the styling class.
*
* @param cnum Class number
* @return Size of class.
*/
int classSize(int cnum);
} ClusterStylingPolicy.java 0000664 0000000 0000000 00000010177 12657057427 0036201 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style package de.lmu.ifi.dbs.elki.visualization.style;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import gnu.trove.list.array.TIntArrayList;
import gnu.trove.map.TObjectIntMap;
import gnu.trove.map.hash.TObjectIntHashMap;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import de.lmu.ifi.dbs.elki.data.Cluster;
import de.lmu.ifi.dbs.elki.data.Clustering;
import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil;
import de.lmu.ifi.dbs.elki.database.ids.DBIDs;
import de.lmu.ifi.dbs.elki.logging.LoggingUtil;
import de.lmu.ifi.dbs.elki.visualization.colors.ColorLibrary;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
/**
* Styling policy based on cluster membership.
*
* @author Erich Schubert
* @since 0.4.0
*
*/
// TODO: fast enough? Some other kind of mapping we can use?
public class ClusterStylingPolicy implements ClassStylingPolicy {
/**
* Object IDs
*/
ArrayList ids;
/**
* Map from cluster objects to color offsets.
*/
TObjectIntMap> cmap;
/**
* Colors
*/
TIntArrayList colors;
/**
* Clustering in use.
*/
Clustering> clustering;
/**
* Constructor.
*
* @param clustering Clustering to use.
*/
public ClusterStylingPolicy(Clustering> clustering, StyleLibrary style) {
super();
this.clustering = clustering;
ColorLibrary colorset = style.getColorSet(StyleLibrary.PLOT);
List extends Cluster>> clusters = clustering.getAllClusters();
ids = new ArrayList<>(clusters.size());
colors = new TIntArrayList(clusters.size());
cmap = new TObjectIntHashMap<>(clusters.size(), .5f, -1);
Iterator extends Cluster>> ci = clusters.iterator();
for (int i = 0; ci.hasNext(); i++) {
Cluster> c = ci.next();
ids.add(DBIDUtil.ensureSet(c.getIDs()));
cmap.put(c, i);
Color col = SVGUtil.stringToColor(colorset.getColor(i));
if (col != null) {
colors.add(col.getRGB());
} else {
LoggingUtil.warning("Unrecognized color name: " + colorset.getColor(i));
}
if (!ci.hasNext()) {
break;
}
}
}
@Override
public int getStyleForDBID(DBIDRef id) {
for (int i = 0; i < ids.size(); i++) {
if (ids.get(i).contains(id)) {
return i;
}
}
return -1;
}
@Override
public int getColorForDBID(DBIDRef id) {
for (int i = 0; i < ids.size(); i++) {
if (ids.get(i).contains(id)) {
return colors.get(i);
}
}
return 0;
}
@Override
public int getMinStyle() {
return 0;
}
@Override
public int getMaxStyle() {
return ids.size();
}
@Override
public DBIDIter iterateClass(int cnum) {
return ids.get(cnum).iter();
}
@Override
public int classSize(int cnum) {
return ids.get(cnum).size();
}
/**
* Get the clustering used by this styling policy
*
* @return Clustering in use
*/
public Clustering> getClustering() {
return clustering;
}
/**
* Get the style number for a cluster.
*
* @param c Cluster
* @return Style number
*/
public int getStyleForCluster(Cluster> c) {
return cmap.get(c);
}
@Override
public String getMenuName() {
return clustering.getLongName();
}
}
PropertiesBasedStyleLibrary.java 0000664 0000000 0000000 00000023571 12657057427 0037471 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style package de.lmu.ifi.dbs.elki.visualization.style;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.utilities.FileUtil;
import de.lmu.ifi.dbs.elki.utilities.FormatUtil;
import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException;
import de.lmu.ifi.dbs.elki.visualization.colors.ColorLibrary;
import de.lmu.ifi.dbs.elki.visualization.colors.ListBasedColorLibrary;
import de.lmu.ifi.dbs.elki.visualization.style.lines.LineStyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.style.lines.SolidLineStyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.style.marker.MarkerLibrary;
import de.lmu.ifi.dbs.elki.visualization.style.marker.PrettyMarkers;
/**
* Style library loading the parameters from a properties file.
*
* @author Erich Schubert
* @since 0.3
*/
// TODO: also use Caching for String values?
public class PropertiesBasedStyleLibrary implements StyleLibrary {
/**
* Logger
*/
private static final Logging LOG = Logging.getLogger(PropertiesBasedStyleLibrary.class);
/**
* Name of the default color scheme.
*/
public static final String DEFAULT_SCHEME_NAME = "Default";
/**
* File name of the default color scheme.
*/
public static final String DEFAULT_SCHEME_FILENAME = "default";
/**
* File extension
*/
public static final String DEFAULT_PROPERTIES_EXTENSION = ".properties";
/**
* Default properties path
*/
private static final String DEFAULT_PROPERTIES_PATH = PropertiesBasedStyleLibrary.class.getPackage().getName().replace('.', File.separatorChar) + File.separatorChar;
/**
* Separator for lists.
*/
public static final String LIST_SEPARATOR = ",";
/**
* Property string for the line style library
*/
public static final String PROP_LINES_LIBRARY = "lines-library";
/**
* Property string for the marker style library
*/
public static final String PROP_MARKER_LIBRARY = "marker-library";
/**
* Properties file to use.
*/
private Properties properties;
/**
* Style scheme name
*/
private String name;
/**
* Cache
*/
private Map cache = new HashMap<>();
/**
* Line style library to use
*/
private LineStyleLibrary linelib = null;
/**
* Marker library to use
*/
private MarkerLibrary markerlib = null;
/**
* Constructor without a properties file name.
*/
public PropertiesBasedStyleLibrary() {
this(DEFAULT_SCHEME_FILENAME, DEFAULT_SCHEME_NAME);
}
/**
* Constructor with a given file name.
*
* @param filename Name of properties file.
* @param name NAme for this style
*/
public PropertiesBasedStyleLibrary(String filename, String name) {
this.properties = new Properties();
this.name = name;
InputStream stream = null;
try {
stream = FileUtil.openSystemFile(filename);
} catch (FileNotFoundException e) {
try {
stream = FileUtil.openSystemFile(filename + DEFAULT_PROPERTIES_EXTENSION);
} catch (FileNotFoundException e2) {
try {
stream = FileUtil.openSystemFile(DEFAULT_PROPERTIES_PATH + filename + DEFAULT_PROPERTIES_EXTENSION);
} catch (FileNotFoundException e3) {
throw new AbortException("Could not find style scheme file '" + filename + "' for scheme '" + name + "'!");
}
}
}
try {
properties.load(stream);
} catch (Exception e) {
throw new AbortException("Error loading properties file " + filename + ".\n", e);
}
}
/**
* Get the style scheme name.
*
* @return the name
*/
protected String getName() {
return name;
}
/**
* Get a value from the cache (to avoid repeated parsing)
*
* @param Type
* @param prefix Tree name
* @param postfix Property name
* @param cls Class restriction
* @return Resulting value
*/
private T getCached(String prefix, String postfix, Class cls) {
return cls.cast(cache.get(prefix + '.' + postfix));
}
/**
* Set a cache value
*
* @param Type
* @param prefix Tree name
* @param postfix Property name
* @param data Data
*/
private void setCached(String prefix, String postfix, T data) {
cache.put(prefix + '.' + postfix, data);
}
/**
* Retrieve the property value for a particular path + type pair.
*
* @param prefix Path
* @param postfix Type
* @return Value
*/
protected String getPropertyValue(String prefix, String postfix) {
String ret = properties.getProperty(prefix + "." + postfix);
if (ret != null) {
// logger.debugFine("Found property: "+prefix + "." +
// postfix+" for "+prefix);
return ret;
}
int pos = prefix.length();
while (pos > 0) {
pos = prefix.lastIndexOf('.', pos - 1);
if (pos <= 0) {
break;
}
ret = properties.getProperty(prefix.substring(0, pos) + '.' + postfix);
if (ret != null) {
// logger.debugFine("Found property: "+prefix.substring(0, pos) + "." +
// postfix+" for "+prefix);
return ret;
}
}
ret = properties.getProperty(postfix);
if (ret != null) {
// logger.debugFine("Found property: "+postfix+" for "+prefix);
return ret;
}
return null;
}
@Override
public String getColor(String key) {
return getPropertyValue(key, COLOR);
}
@Override
public String getBackgroundColor(String key) {
return getPropertyValue(key, BACKGROUND_COLOR);
}
@Override
public String getTextColor(String key) {
return getPropertyValue(key, TEXT_COLOR);
}
@Override
public ColorLibrary getColorSet(String key) {
ColorLibrary cl = getCached(key, COLORSET, ColorLibrary.class);
if (cl == null) {
String[] colors = getPropertyValue(key, COLORSET).split(LIST_SEPARATOR);
cl = new ListBasedColorLibrary(colors, "Default");
setCached(key, COLORSET, cl);
}
return cl;
}
@Override
public double getLineWidth(String key) {
Double lw = getCached(key, LINE_WIDTH, Double.class);
if (lw == null) {
try {
lw = Double.valueOf(FormatUtil.parseDouble(getPropertyValue(key, LINE_WIDTH)) * SCALE);
} catch (NullPointerException e) {
throw new AbortException("Missing/invalid value in style library: " + key + '.' + LINE_WIDTH);
}
}
return lw.doubleValue();
}
@Override
public double getTextSize(String key) {
Double lw = getCached(key, TEXT_SIZE, Double.class);
if (lw == null) {
try {
lw = Double.valueOf(FormatUtil.parseDouble(getPropertyValue(key, TEXT_SIZE)) * SCALE);
} catch (NullPointerException e) {
throw new AbortException("Missing/invalid value in style library: " + key + '.' + TEXT_SIZE);
}
}
return lw.doubleValue();
}
@Override
public String getFontFamily(String key) {
return getPropertyValue(key, FONT_FAMILY);
}
@Override
public double getSize(String key) {
Double lw = getCached(key, GENERIC_SIZE, Double.class);
if (lw == null) {
try {
lw = Double.valueOf(FormatUtil.parseDouble(getPropertyValue(key, GENERIC_SIZE)) * SCALE);
} catch (NullPointerException e) {
throw new AbortException("Missing/invalid value in style library: " + key + '.' + GENERIC_SIZE);
}
}
return lw.doubleValue();
}
@Override
public double getOpacity(String key) {
Double lw = getCached(key, OPACITY, Double.class);
if (lw == null) {
try {
lw = Double.valueOf(FormatUtil.parseDouble(getPropertyValue(key, OPACITY)));
} catch (NullPointerException e) {
throw new AbortException("Missing/invalid value in style library: " + key + '.' + OPACITY);
}
}
return lw.doubleValue();
}
@Override
public LineStyleLibrary lines() {
if (linelib == null) {
String libname = properties.getProperty(PROP_LINES_LIBRARY, SolidLineStyleLibrary.class.getName());
try {
Class> cls;
try {
cls = Class.forName(libname);
} catch (ClassNotFoundException e) {
cls = Class.forName(LineStyleLibrary.class.getPackage().getName() + '.' + libname);
}
linelib = (LineStyleLibrary) cls.getConstructor(StyleLibrary.class).newInstance(this);
} catch (Exception e) {
LOG.exception(e);
linelib = new SolidLineStyleLibrary(this);
}
}
return linelib;
}
@Override
public MarkerLibrary markers() {
if (markerlib == null) {
String libname = properties.getProperty(PROP_MARKER_LIBRARY, PrettyMarkers.class.getName());
try {
Class> cls;
try {
cls = Class.forName(libname);
} catch (ClassNotFoundException e) {
cls = Class.forName(MarkerLibrary.class.getPackage().getName() + '.' + libname);
}
markerlib = (MarkerLibrary) cls.getConstructor(StyleLibrary.class).newInstance(this);
} catch (Exception e) {
LOG.exception(e);
markerlib = new PrettyMarkers(this);
}
}
return markerlib;
}
}
SingleObjectsStylingPolicy.java 0000664 0000000 0000000 00000002372 12657057427 0037311 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style package de.lmu.ifi.dbs.elki.visualization.style;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
/**
* Styling policy based on assigning objects individual colors.
*
* @author Erich Schubert
* @since 0.4.0
*/
public interface SingleObjectsStylingPolicy extends StylingPolicy {
// TODO: finish and use, e.g. for outliers and density visualization
// TODO: do we need anything here beyond "not a class styling policy"?
}
StyleLibrary.java 0000775 0000000 0000000 00000013150 12657057427 0034450 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style package de.lmu.ifi.dbs.elki.visualization.style;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.visualization.colors.ColorLibrary;
import de.lmu.ifi.dbs.elki.visualization.style.lines.LineStyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.style.marker.MarkerLibrary;
/**
* Style library interface. A style library allows the user to customize the
* visual rendering, for example for print media or screen presentation without
* having to change program code.
*
* @author Erich Schubert
* @since 0.3
*
* @apiviz.composedOf ColorLibrary
* @apiviz.composedOf LineStyleLibrary
* @apiviz.composedOf MarkerLibrary
*/
public interface StyleLibrary {
/**
* Default
*/
final static String DEFAULT = "";
/**
* Page
*/
final static String PAGE = "page";
/**
* Plot
*/
final static String PLOT = "plot";
/**
* Axis
*/
final static String AXIS = "axis";
/**
* Axis tick
*/
final static String AXIS_TICK = "axis.tick";
/**
* Axis minor tick
*/
final static String AXIS_TICK_MINOR = "axis.tick.minor";
/**
* Axis label
*/
final static String AXIS_LABEL = "axis.label";
/**
* Key
*/
final static String KEY = "key";
/**
* Clusterorder
*/
final static String CLUSTERORDER = "plot.clusterorder";
/**
* Margin
*/
final static String MARGIN = "margin";
/**
* Bubble size
*/
final static String BUBBLEPLOT = "plot.bubble";
/**
* Marker size
*/
final static String MARKERPLOT = "plot.marker";
/**
* Dot size
*/
final static String DOTPLOT = "plot.dot";
/**
* Grayed out objects
*/
final static String PLOTGREY = "plot.grey";
/**
* Reference points color and size
*/
final static String REFERENCE_POINTS = "plot.referencepoints";
/**
* Polygons style
*/
final static String POLYGONS = "plot.polygons";
/**
* Selection color and opacity
*/
final static String SELECTION = "plot.selection";
/**
* Selection color and opacity during selecting process
*/
final static String SELECTION_ACTIVE = "plot.selection.active";
/**
* Scaling constant. Keep in sync with
* {@link de.lmu.ifi.dbs.elki.visualization.projections.Projection#SCALE}
*/
public static final double SCALE = 100.0;
/* ** Property types ** */
/**
* Color
*/
final static String COLOR = "color";
/**
* Background color
*/
final static String BACKGROUND_COLOR = "background-color";
/**
* Text color
*/
final static String TEXT_COLOR = "text-color";
/**
* Color set
*/
final static String COLORSET = "colorset";
/**
* Line width
*/
final static String LINE_WIDTH = "line-width";
/**
* Text size
*/
final static String TEXT_SIZE = "text-size";
/**
* Font family
*/
final static String FONT_FAMILY = "font-family";
/**
* Generic size
*/
final static String GENERIC_SIZE = "size";
/**
* Opacity (transparency)
*/
final static String OPACITY = "opacity";
/**
* XY curve styling.
*/
static final String XYCURVE = "xycurve";
/**
* Retrieve a color for an item
*
* @param name Reference name
* @return color in CSS/SVG valid format: hexadecimal (#aabbcc) or names such
* as "red"
*/
public String getColor(String name);
/**
* Retrieve background color for an item
*
* @param name Reference name
* @return color in CSS/SVG valid format: hexadecimal (#aabbcc) or names such
* as "red"
*/
public String getBackgroundColor(String name);
/**
* Retrieve text color for an item
*
* @param name Reference name
* @return color in CSS/SVG valid format: hexadecimal (#aabbcc) or names such
* as "red"
*/
public String getTextColor(String name);
/**
* Retrieve colorset for an item
*
* @param name Reference name
* @return color library
*/
public ColorLibrary getColorSet(String name);
/**
* Get line width
*
* @param key Key
* @return line width as double
*/
public double getLineWidth(String key);
/**
* Get generic size
*
* @param key Key
* @return size as double
*/
public double getSize(String key);
/**
* Get text size
*
* @param key Key
* @return line width as double
*/
public double getTextSize(String key);
/**
* Get font family
*
* @param key Key
* @return font family CSS string
*/
public String getFontFamily(String key);
/**
* Get opacity
*
* @param key Key
* @return size as double
*/
public double getOpacity(String key);
/**
* Get the line style library to use.
*
* @return line style library
*/
public LineStyleLibrary lines();
/**
* Get the marker library to use.
*
* @return marker library
*/
public MarkerLibrary markers();
} StylingPolicy.java 0000664 0000000 0000000 00000003124 12657057427 0034631 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style package de.lmu.ifi.dbs.elki.visualization.style;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
import de.lmu.ifi.dbs.elki.visualization.VisualizationItem;
/**
* Styling policy.
*
* Implementations must implement either {@link ClassStylingPolicy} or
* {@link SingleObjectsStylingPolicy} interfaces, as most visualizers will only
* support these known interfaces.
*
* @author Erich Schubert
* @since 0.4.0
*/
public interface StylingPolicy extends VisualizationItem {
/**
* Get the color for an individual object.
*
* Note: if possible, use a class styling policy which can optimize better.
*
* @param id Object ID
* @return Color value
*/
public int getColorForDBID(DBIDRef id);
}
elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/lines/ 0000775 0000000 0000000 00000000000 12657057427 0032346 5 ustar 00root root 0000000 0000000 DashedLineStyleLibrary.java 0000664 0000000 0000000 00000011445 12657057427 0037505 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/lines package de.lmu.ifi.dbs.elki.visualization.style.lines;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.apache.batik.util.CSSConstants;
import de.lmu.ifi.dbs.elki.visualization.colors.ColorLibrary;
import de.lmu.ifi.dbs.elki.visualization.css.CSSClass;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
/**
* Line library using various dashed and dotted line styles.
*
* This library is particularly useful for black and white output.
*
* {@link LineStyleLibrary#FLAG_STRONG} will result in thicker lines.
*
* {@link LineStyleLibrary#FLAG_WEAK} will result in thinner and
* semi-transparent lines.
*
* {@link LineStyleLibrary#FLAG_INTERPOLATED} will result in shorter dashing
* patterns.
*
* @author Erich Schubert
* @since 0.3
*
* @apiviz.composedOf ColorLibrary
*/
public class DashedLineStyleLibrary implements LineStyleLibrary {
/**
* The style library we use for colors
*/
private ColorLibrary colors;
/** Dash patterns to regularly use */
private double[][] dashpatterns = {
// solid, no dashing
{},
// half-half
{ .5, .5 },
// quarters
{ .25, .25, .25, .25 },
// alternating long-quart
{ .75, .25 },
// dash-dot
{ .7, .1, .1, .1 }, };
/** Replacement for the solid pattern in 'interpolated' mode */
private double[] solidreplacement = { .1, .1 };
private int dashnum = dashpatterns.length;
/**
* Color of "uncolored" dots
*/
private String dotcolor;
/**
* Color of "greyed out" dots
*/
private String greycolor;
/**
* Constructor
*
* @param style Style library
*/
public DashedLineStyleLibrary(StyleLibrary style) {
super();
this.colors = style.getColorSet(StyleLibrary.PLOT);
this.dotcolor = style.getColor(StyleLibrary.MARKERPLOT);
this.greycolor = style.getColor(StyleLibrary.PLOTGREY);
}
@Override
public void formatCSSClass(CSSClass cls, int style, double width, Object... flags) {
if(style == -2) {
cls.setStatement(CSSConstants.CSS_STROKE_PROPERTY, greycolor);
}
else if(style == -1) {
cls.setStatement(CSSConstants.CSS_STROKE_PROPERTY, dotcolor);
}
else {
cls.setStatement(CSSConstants.CSS_STROKE_PROPERTY, colors.getColor(style));
}
boolean interpolated = false;
// process flavoring flags
for(Object flag : flags) {
if(LineStyleLibrary.FLAG_STRONG.equals(flag)) {
width = width * 1.5;
}
else if(LineStyleLibrary.FLAG_WEAK.equals(flag)) {
cls.setStatement(CSSConstants.CSS_STROKE_OPACITY_PROPERTY, ".50");
width = width * 0.75;
}
else if(LineStyleLibrary.FLAG_INTERPOLATED.equals(flag)) {
interpolated = true;
}
}
cls.setStatement(CSSConstants.CSS_STROKE_WIDTH_PROPERTY, SVGUtil.fmt(width));
// handle dashing
int styleflav = (style > 0) ? (style % dashnum) : (-style % dashnum);
if(!interpolated) {
double[] pat = dashpatterns[styleflav];
assert (pat.length % 2 == 0);
if(pat.length > 0) {
StringBuilder pattern = new StringBuilder();
for(int i = 0; i < pat.length; i++) {
if(i > 0) {
pattern.append(',');
}
pattern.append(SVGUtil.fmt(pat[i] * width * 30));
// pattern.append("%");
}
cls.setStatement(CSSConstants.CSS_STROKE_DASHARRAY_PROPERTY, pattern.toString());
}
}
else {
double[] pat = dashpatterns[styleflav];
if(styleflav == 0) {
pat = solidreplacement;
}
assert (pat.length % 2 == 0);
// TODO: add dotting.
if(pat.length > 0) {
StringBuilder pattern = new StringBuilder();
for(int i = 0; i < pat.length; i++) {
if(i > 0) {
pattern.append(',');
}
pattern.append(SVGUtil.fmt(pat[i] * width));
// pattern.append("%");
}
cls.setStatement(CSSConstants.CSS_STROKE_DASHARRAY_PROPERTY, pattern.toString());
}
}
}
} LineStyleLibrary.java 0000664 0000000 0000000 00000004714 12657057427 0036375 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/lines package de.lmu.ifi.dbs.elki.visualization.style.lines;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.visualization.css.CSSClass;
/**
* Interface to obtain CSS classes for plot lines.
*
* {@code meta} is a set of Objects, usually constants that may or may not be
* used by the {@link LineStyleLibrary} to generate variants of the style.
*
* Predefined meta flags that are usually supported are:
*
*
{@link #FLAG_STRONG}
*
Request a "stronger" version of the same style
*
{@link #FLAG_WEAK}
*
Request a "weaker" version of the same style
*
{@link #FLAG_INTERPOLATED}
*
Request an "interpolated" version of the same style (e.g. lighter or
* dashed)
*
*
* @author Erich Schubert
* @since 0.3
*
* @apiviz.uses CSSClass oneway
*/
public interface LineStyleLibrary {
/**
* Meta flag to request a 'stronger' version of the style
*/
public static final String FLAG_STRONG = "strong";
/**
* Meta flag to request a 'weaker' version of the style
*/
public static final String FLAG_WEAK = "weak";
/**
* Meta flag to request an 'interpolated' version of the style
*/
public static final String FLAG_INTERPOLATED = "interpolated";
/**
* Add the formatting statements to the given CSS class.
*
* Note: this can overwrite some existing properties of the CSS class.
*
* @param cls CSS class to modify
* @param style style number
* @param width line width
* @param meta meta objects to request line variants
*/
public void formatCSSClass(CSSClass cls, int style, double width, Object... meta);
}
SolidLineStyleLibrary.java 0000664 0000000 0000000 00000006601 12657057427 0037365 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/lines package de.lmu.ifi.dbs.elki.visualization.style.lines;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.apache.batik.util.CSSConstants;
import de.lmu.ifi.dbs.elki.visualization.colors.ColorLibrary;
import de.lmu.ifi.dbs.elki.visualization.css.CSSClass;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
/**
* Line style library featuring solid lines for default styles only (combine
* with a color library to obtain enough classes!)
*
* {@link LineStyleLibrary#FLAG_STRONG} will result in thicker lines.
*
* {@link LineStyleLibrary#FLAG_WEAK} will result in thinner and
* semi-transparent lines.
*
* {@link LineStyleLibrary#FLAG_INTERPOLATED} will result in dashed lines.
*
* @author Erich Schubert
* @since 0.3
*
* @apiviz.composedOf ColorLibrary
*/
public class SolidLineStyleLibrary implements LineStyleLibrary {
/**
* Reference to the color library.
*/
private ColorLibrary colors;
/**
* Color of "uncolored" dots
*/
private String dotcolor;
/**
* Color of "greyed out" dots
*/
private String greycolor;
/**
* Constructor.
*
* @param style Style library to use.
*/
public SolidLineStyleLibrary(StyleLibrary style) {
super();
this.colors = style.getColorSet(StyleLibrary.PLOT);
this.dotcolor = style.getColor(StyleLibrary.MARKERPLOT);
this.greycolor = style.getColor(StyleLibrary.PLOTGREY);
}
@Override
public void formatCSSClass(CSSClass cls, int style, double width, Object... flags) {
if(style == -2) {
cls.setStatement(CSSConstants.CSS_STROKE_PROPERTY, greycolor);
}
else if(style == -1) {
cls.setStatement(CSSConstants.CSS_STROKE_PROPERTY, dotcolor);
}
else {
cls.setStatement(CSSConstants.CSS_STROKE_PROPERTY, colors.getColor(style));
}
boolean interpolated = false;
// process flavoring flags
for(Object flag : flags) {
if(LineStyleLibrary.FLAG_STRONG.equals(flag)) {
width = width * 1.5;
}
else if(LineStyleLibrary.FLAG_WEAK.equals(flag)) {
cls.setStatement(CSSConstants.CSS_STROKE_OPACITY_PROPERTY, ".50");
width = width * 0.75;
}
else if(LineStyleLibrary.FLAG_INTERPOLATED.equals(flag)) {
interpolated = true;
}
}
cls.setStatement(CSSConstants.CSS_STROKE_WIDTH_PROPERTY, SVGUtil.fmt(width));
if(interpolated) {
cls.setStatement(CSSConstants.CSS_STROKE_DASHARRAY_PROPERTY, "" + SVGUtil.fmt(width / StyleLibrary.SCALE * 2.) + "," + SVGUtil.fmt(width / StyleLibrary.SCALE * 2.));
}
}
}
package-info.java 0000775 0000000 0000000 00000001760 12657057427 0035465 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/lines /**
*
Generate line styles for plotting in CSS
*
*/
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.lmu.ifi.dbs.elki.visualization.style.lines; elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker/ 0000775 0000000 0000000 00000000000 12657057427 0032515 5 ustar 00root root 0000000 0000000 CircleMarkers.java 0000664 0000000 0000000 00000005015 12657057427 0036030 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker package de.lmu.ifi.dbs.elki.visualization.style.marker;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
import de.lmu.ifi.dbs.elki.visualization.colors.ColorLibrary;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGPlot;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
/**
* Simple marker library that just draws colored circles at the given
* coordinates.
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.composedOf ColorLibrary
*/
public class CircleMarkers implements MarkerLibrary {
/**
* Color library
*/
private ColorLibrary colors;
/**
* Color of "uncolored" dots
*/
private String dotcolor = "black";
/**
* Color of "greyed out" dots
*/
private String greycolor = "gray";
/**
* Constructor
*
* @param style Style library to use
*/
public CircleMarkers(StyleLibrary style) {
super();
this.colors = style.getColorSet(StyleLibrary.MARKERPLOT);
this.dotcolor = style.getColor(StyleLibrary.MARKERPLOT);
this.greycolor = style.getColor(StyleLibrary.PLOTGREY);
}
/**
* Use a given marker on the document.
*/
@Override
public Element useMarker(SVGPlot plot, Element parent, double x, double y, int stylenr, double size) {
Element marker = plot.svgCircle(x, y, size * .5);
final String col;
if(stylenr == -1) {
col = dotcolor;
}
else if(stylenr == -2) {
col = greycolor;
}
else {
col = colors.getColor(stylenr);
}
SVGUtil.setStyle(marker, SVGConstants.CSS_FILL_PROPERTY + ":" + col);
parent.appendChild(marker);
return marker;
}
} MarkerLibrary.java 0000775 0000000 0000000 00000003762 12657057427 0036062 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker package de.lmu.ifi.dbs.elki.visualization.style.marker;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.w3c.dom.Element;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGPlot;
/**
* A marker library is a class that can generate and draw various styles of
* markers. Different uses might require different marker libraries (e.g. full
* screen, thumbnail, print)
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.uses Element oneway - - «create»
*/
public interface MarkerLibrary {
/**
* Insert a marker at the given coordinates. Markers will be defined in the
* defs part of the document, and then SVG-"use"d at the given coordinates.
* This supposedly is more efficient and significantly reduces file size.
* Symbols will be named "s0", "s1" etc.; these names must not be used by
* other elements in the SVG document!
*
* @param plot Plot to draw on
* @param parent parent node
* @param x coordinate
* @param y coordinate
* @param style style (enumerated)
* @param size size
* @return Element node generated.
*/
public Element useMarker(SVGPlot plot, Element parent, double x, double y, int style, double size);
} MinimalMarkers.java 0000775 0000000 0000000 00000005051 12657057427 0036220 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker package de.lmu.ifi.dbs.elki.visualization.style.marker;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
import de.lmu.ifi.dbs.elki.visualization.colors.ColorLibrary;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGPlot;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
/**
* Simple marker library that just draws colored rectangles at the given
* coordinates.
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.composedOf ColorLibrary
*/
public class MinimalMarkers implements MarkerLibrary {
/**
* Color library
*/
private ColorLibrary colors;
/**
* Color of "uncolored" dots
*/
private String dotcolor = "black";
/**
* Color of "greyed out" dots
*/
private String greycolor = "gray";
/**
* Constructor
*
* @param style Style library to use
*/
public MinimalMarkers(StyleLibrary style) {
super();
this.colors = style.getColorSet(StyleLibrary.MARKERPLOT);
this.dotcolor = style.getColor(StyleLibrary.MARKERPLOT);
this.greycolor = style.getColor(StyleLibrary.PLOTGREY);
}
/**
* Use a given marker on the document.
*/
@Override
public Element useMarker(SVGPlot plot, Element parent, double x, double y, int stylenr, double size) {
Element marker = plot.svgRect(x - size * .5, y - size * .5, size, size);
final String col;
if(stylenr == -1) {
col = dotcolor;
}
else if(stylenr == -2) {
col = greycolor;
}
else {
col = colors.getColor(stylenr);
}
SVGUtil.setStyle(marker, SVGConstants.CSS_FILL_PROPERTY + ":" + col);
parent.appendChild(marker);
return marker;
}
} PrettyMarkers.java 0000775 0000000 0000000 00000017256 12657057427 0036133 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker package de.lmu.ifi.dbs.elki.visualization.style.marker;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
import de.lmu.ifi.dbs.elki.visualization.colors.ColorLibrary;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGPlot;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
/**
* Marker library achieving a larger number of styles by combining different
* shapes with different colors. Uses object ID management by SVGPlot.
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.composedOf ColorLibrary
*/
public class PrettyMarkers implements MarkerLibrary {
/**
* Color library
*/
private ColorLibrary colors;
/**
* Default prefix to use.
*/
private static final String DEFAULT_PREFIX = "s";
/**
* Prefix for the IDs generated.
*/
private String prefix;
/**
* Color of "uncolored" dots
*/
private String dotcolor;
/**
* Color of "greyed out" dots
*/
private String greycolor;
/**
* Constructor
*
* @param prefix prefix to use.
* @param style style library to use
*/
public PrettyMarkers(String prefix, StyleLibrary style) {
this.prefix = prefix;
this.colors = style.getColorSet(StyleLibrary.MARKERPLOT);
this.dotcolor = style.getColor(StyleLibrary.MARKERPLOT);
this.greycolor = style.getColor(StyleLibrary.PLOTGREY);
}
/**
* Constructor without prefix argument, will use {@link #DEFAULT_PREFIX} as
* prefix.
*
* @param style Style library to use
*/
public PrettyMarkers(StyleLibrary style) {
this(DEFAULT_PREFIX, style);
}
/**
* Draw an marker used in scatter plots. If you intend to use the markers
* multiple times, you should consider using the {@link #useMarker} method
* instead, which exploits the SVG features of symbol definition and use
*
* @param plot containing plot
* @param parent parent node
* @param x position
* @param y position
* @param style marker style (enumerated)
* @param size size
*/
public void plotMarker(SVGPlot plot, Element parent, double x, double y, int style, double size) {
assert (parent != null);
if (style == -1) {
plotUncolored(plot, parent, x, y, size);
return;
}
if (style == -2) {
plotGray(plot, parent, x, y, size);
return;
}
// TODO: add more styles.
String colorstr = colors.getColor(style);
String strokestyle = SVGConstants.CSS_STROKE_PROPERTY + ":" + colorstr + ";" + SVGConstants.CSS_STROKE_WIDTH_PROPERTY + ":" + SVGUtil.fmt(size / 6);
switch(style % 8){
case 0: {
// + cross
Element line1 = plot.svgLine(x, y - size / 2.2, x, y + size / 2.2);
SVGUtil.setStyle(line1, strokestyle);
parent.appendChild(line1);
Element line2 = plot.svgLine(x - size / 2.2, y, x + size / 2.2, y);
SVGUtil.setStyle(line2, strokestyle);
parent.appendChild(line2);
break;
}
case 1: {
// X cross
Element line1 = plot.svgLine(x - size / 2.828427, y - size / 2.828427, x + size / 2.828427, y + size / 2.828427);
SVGUtil.setStyle(line1, strokestyle);
parent.appendChild(line1);
Element line2 = plot.svgLine(x - size / 2.828427, y + size / 2.828427, x + size / 2.828427, y - size / 2.828427);
SVGUtil.setStyle(line2, strokestyle);
parent.appendChild(line2);
break;
}
case 2: {
// O hollow circle
Element circ = plot.svgCircle(x, y, size / 2.2);
SVGUtil.setStyle(circ, "fill: none;" + strokestyle);
parent.appendChild(circ);
break;
}
case 3: {
// [] hollow rectangle
Element rect = plot.svgRect(x - size / 2.4, y - size / 2.4, size / 1.2, size / 1.2);
SVGUtil.setStyle(rect, "fill: none;" + strokestyle);
parent.appendChild(rect);
break;
}
case 4: {
// <> hollow diamond
Element rect = plot.svgRect(x - size / 2.7, y - size / 2.7, size / 1.35, size / 1.35);
SVGUtil.setStyle(rect, "fill: none;" + strokestyle);
SVGUtil.setAtt(rect, SVGConstants.SVG_TRANSFORM_ATTRIBUTE, "rotate(45," + SVGUtil.fmt(x) + "," + SVGUtil.fmt(y) + ")");
parent.appendChild(rect);
break;
}
case 5: {
// O filled circle
Element circ = plot.svgCircle(x, y, size * .5);
SVGUtil.setStyle(circ, SVGConstants.CSS_FILL_PROPERTY + ":" + colorstr);
parent.appendChild(circ);
break;
}
case 6: {
// [] filled rectangle
Element rect = plot.svgRect(x - size / 2.2, y - size / 2.2, size / 1.1, size / 1.1);
SVGUtil.setStyle(rect, "fill:" + colorstr);
parent.appendChild(rect);
break;
}
case 7: {
// <> filled diamond
Element rect = plot.svgRect(x - size / 2.5, y - size / 2.5, size / 1.25, size / 1.25);
SVGUtil.setStyle(rect, "fill:" + colorstr);
SVGUtil.setAtt(rect, SVGConstants.SVG_TRANSFORM_ATTRIBUTE, "rotate(45," + SVGUtil.fmt(x) + "," + SVGUtil.fmt(y) + ")");
parent.appendChild(rect);
break;
}
}
}
/**
* Plot a replacement marker when an object is to be plotted as "disabled", usually gray.
*
* @param plot Plot to draw to
* @param parent Parent element
* @param x X position
* @param y Y position
* @param size Size
*/
protected void plotGray(SVGPlot plot, Element parent, double x, double y, double size) {
Element marker = plot.svgCircle(x, y, size * .5);
SVGUtil.setStyle(marker, SVGConstants.CSS_FILL_PROPERTY + ":" + greycolor);
parent.appendChild(marker);
}
/**
* Plot a replacement marker when no color is set; usually black
*
* @param plot Plot to draw to
* @param parent Parent element
* @param x X position
* @param y Y position
* @param size Size
*/
protected void plotUncolored(SVGPlot plot, Element parent, double x, double y, double size) {
Element marker = plot.svgCircle(x, y, size * .5);
SVGUtil.setStyle(marker, SVGConstants.CSS_FILL_PROPERTY + ":" + dotcolor);
parent.appendChild(marker);
}
@Override
public Element useMarker(SVGPlot plot, Element parent, double x, double y, int style, double size) {
String id = prefix + style + "_" + size;
Element existing = plot.getIdElement(id);
if(existing == null) {
Element symbol = plot.svgElement(SVGConstants.SVG_SYMBOL_TAG);
SVGUtil.setAtt(symbol, SVGConstants.SVG_ID_ATTRIBUTE, id);
plotMarker(plot, symbol, 2 * size, 2 * size, style, 2 * size);
plot.getDefs().appendChild(symbol);
plot.putIdElement(id, symbol);
}
Element use = plot.svgElement(SVGConstants.SVG_USE_TAG);
use.setAttributeNS(SVGConstants.XLINK_NAMESPACE_URI, SVGConstants.XLINK_HREF_QNAME, "#" + id);
SVGUtil.setAtt(use, SVGConstants.SVG_X_ATTRIBUTE, x - 2 * size);
SVGUtil.setAtt(use, SVGConstants.SVG_Y_ATTRIBUTE, y - 2 * size);
if(parent != null) {
parent.appendChild(use);
}
return use;
}
} package-info.java 0000775 0000000 0000000 00000001711 12657057427 0035630 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker /**
*
Draw plot markers
*
*/
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.lmu.ifi.dbs.elki.visualization.style.marker; package-info.java 0000775 0000000 0000000 00000001732 12657057427 0034352 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style /**
*
Style management for ELKI visualizations.
*
*/
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.lmu.ifi.dbs.elki.visualization.style; elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/svg/ 0000775 0000000 0000000 00000000000 12657057427 0030673 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/svg/SVGArrow.java 0000664 0000000 0000000 00000005631 12657057427 0033215 0 ustar 00root root 0000000 0000000 package de.lmu.ifi.dbs.elki.visualization.svg;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.w3c.dom.Element;
/**
* Static class for drawing simple arrows
*
* @author Erich Schubert
* @author Robert Rödler
* @since 0.5.5
*
* @apiviz.uses SVGPath
*/
public final class SVGArrow {
/**
* Direction constants
*
* @author Erich Schubert
* @author Robert Rödler
*
* @apiviz.exclude
*/
public static enum Direction {
LEFT, DOWN, RIGHT, UP, // SWAPWITH, INSERT
}
/**
* Constant for "up"
*/
public static final Direction UP = Direction.UP;
/**
* Constant for "down"
*/
public static final Direction DOWN = Direction.DOWN;
/**
* Constant for "right"
*/
public static final Direction RIGHT = Direction.RIGHT;
/**
* Constant for "left"
*/
public static final Direction LEFT = Direction.LEFT;
/**
* Draw an arrow at the given position.
*
* Note: the arrow is an unstyled svg path. You need to apply style afterwards.
*
* @param svgp Plot to draw to
* @param dir Direction to draw
* @param x Center x coordinate
* @param y Center y coordinate
* @param size Arrow size
* @return SVG Element
*/
public static Element makeArrow(SVGPlot svgp, Direction dir, double x, double y, double size) {
final SVGPath path = new SVGPath();
final double hs = size / 2.;
switch(dir){
case LEFT:
path.drawTo(x + hs, y + hs);
path.drawTo(x - hs, y);
path.drawTo(x + hs, y - hs);
path.drawTo(x + hs, y + hs);
break;
case DOWN:
path.drawTo(x - hs, y - hs);
path.drawTo(x + hs, y - hs);
path.drawTo(x, y + hs);
path.drawTo(x - hs, y - hs);
break;
case RIGHT:
path.drawTo(x - hs, y - hs);
path.drawTo(x + hs, y);
path.drawTo(x - hs, y + hs);
path.drawTo(x - hs, y - hs);
break;
case UP:
path.drawTo(x - hs, y + hs);
path.drawTo(x, y - hs);
path.drawTo(x + hs, y + hs);
path.drawTo(x - hs, y + hs);
break;
}
path.close();
return path.makeElement(svgp);
}
} elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/svg/SVGButton.java0000664 0000000 0000000 00000011205 12657057427 0033370 0 ustar 00root root 0000000 0000000 package de.lmu.ifi.dbs.elki.visualization.svg;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
import de.lmu.ifi.dbs.elki.visualization.css.CSSClass;
/**
* Class to draw a button as SVG.
*
* @author Erich Schubert
* @since 0.5.0
*/
public class SVGButton {
/**
* Default button color
*/
public static final String DEFAULT_BUTTON_COLOR = SVGConstants.CSS_LIGHTGRAY_VALUE;
/**
* Default text color
*/
public static final String DEFAULT_TEXT_COLOR = SVGConstants.CSS_BLACK_VALUE;
/**
* X position
*/
private double x;
/**
* Y position
*/
private double y;
/**
* Width
*/
private double w;
/**
* Height
*/
private double h;
/**
* Corner rounding factor. NaN = no rounding
*/
private double r = Double.NaN;
/**
* Class for the buttons main CSS
*/
private CSSClass butcss;
/**
* Button title, optional
*/
private String title = null;
/**
* Title styling
*/
private CSSClass titlecss = null;
/**
* Constructor.
*
* @param x Position X
* @param y Position Y
* @param w Width
* @param h Height
* @param r Rounded radius
*/
public SVGButton(double x, double y, double w, double h, double r) {
super();
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.r = r;
this.butcss = new CSSClass(this, "button");
butcss.setStatement(SVGConstants.CSS_FILL_PROPERTY, DEFAULT_BUTTON_COLOR);
butcss.setStatement(SVGConstants.CSS_STROKE_PROPERTY, SVGConstants.CSS_BLACK_VALUE);
butcss.setStatement(SVGConstants.CSS_STROKE_WIDTH_PROPERTY, ".01");
}
/**
* Produce the actual SVG elements for the button.
*
* @param svgp Plot to draw to
* @return Button wrapper element
*/
public Element render(SVGPlot svgp) {
Element tag = svgp.svgElement(SVGConstants.SVG_G_TAG);
Element button = svgp.svgRect(x, y, w, h);
if(!Double.isNaN(r)) {
SVGUtil.setAtt(button, SVGConstants.SVG_RX_ATTRIBUTE, r);
SVGUtil.setAtt(button, SVGConstants.SVG_RY_ATTRIBUTE, r);
}
SVGUtil.setAtt(button, SVGConstants.SVG_STYLE_ATTRIBUTE, butcss.inlineCSS());
tag.appendChild(button);
// Add light effect:
if (svgp.getIdElement(SVGEffects.LIGHT_GRADIENT_ID) != null) {
Element light = svgp.svgRect(x, y, w, h);
if(!Double.isNaN(r)) {
SVGUtil.setAtt(light, SVGConstants.SVG_RX_ATTRIBUTE, r);
SVGUtil.setAtt(light, SVGConstants.SVG_RY_ATTRIBUTE, r);
}
SVGUtil.setAtt(light, SVGConstants.SVG_STYLE_ATTRIBUTE, "fill:url(#"+SVGEffects.LIGHT_GRADIENT_ID+");fill-opacity:.5");
tag.appendChild(light);
}
// Add shadow effect:
if(svgp.getIdElement(SVGEffects.SHADOW_ID) != null) {
//Element shadow = svgp.svgRect(x + (w * .05), y + (h * .05), w, h);
//SVGUtil.setAtt(button, SVGConstants.SVG_STYLE_ATTRIBUTE, SVGConstants.CSS_FILL_PROPERTY + ":" + SVGConstants.CSS_BLACK_VALUE);
button.setAttribute(SVGConstants.SVG_FILTER_ATTRIBUTE, "url(#" + SVGEffects.SHADOW_ID + ")");
//tag.appendChild(shadow);
}
if(title != null) {
Element label = svgp.svgText(x + w * .5, y + h * .7, title);
label.setAttribute(SVGConstants.SVG_STYLE_ATTRIBUTE, titlecss.inlineCSS());
tag.appendChild(label);
}
return tag;
}
/**
* Set the button title
*
* @param title Button title
* @param textcolor Color
*/
public void setTitle(String title, String textcolor) {
this.title = title;
if(titlecss == null) {
titlecss = new CSSClass(this, "text");
titlecss.setStatement(SVGConstants.CSS_TEXT_ANCHOR_PROPERTY, SVGConstants.CSS_MIDDLE_VALUE);
titlecss.setStatement(SVGConstants.CSS_FILL_PROPERTY, textcolor);
titlecss.setStatement(SVGConstants.CSS_FONT_SIZE_PROPERTY, .6 * h);
}
}
} SVGCheckbox.java 0000664 0000000 0000000 00000012121 12657057427 0033562 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/svg package de.lmu.ifi.dbs.elki.visualization.svg;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.EventListenerList;
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventListener;
import org.w3c.dom.events.EventTarget;
/**
* SVG checkbox.
*
* @author Sascha Goldhofer
* @since 0.5.0
*/
public class SVGCheckbox {
/**
* Status flag
*/
protected boolean checked;
/**
* Event listeners
*/
protected EventListenerList listenerList = new EventListenerList();
/**
* Checkbox label
*/
protected String label = null;
/**
* Constructor, without label
*
* @param checked Checked status
*/
public SVGCheckbox(boolean checked) {
this(checked, null);
}
/**
* Constructor, with label
*
* @param checked Checked status
* @param label Label
*/
public SVGCheckbox(boolean checked, String label) {
this.checked = checked;
this.label = label;
}
/**
* Render the SVG checkbox to a plot
*
* @param svgp Plot to draw to
* @param x X offset
* @param y Y offset
* @param size Size factor
* @return Container element
*/
public Element renderCheckBox(SVGPlot svgp, double x, double y, double size) {
// create check
final Element checkmark = SVGEffects.makeCheckmark(svgp);
checkmark.setAttribute(SVGConstants.SVG_TRANSFORM_ATTRIBUTE, "scale(" + (size / 11) + ") translate(" + x + " " + y + ")");
if(!checked) {
checkmark.setAttribute(SVGConstants.SVG_STYLE_ATTRIBUTE, SVGConstants.CSS_DISPLAY_PROPERTY + ":" + SVGConstants.CSS_NONE_VALUE);
}
// create box
Element checkbox_box = SVGUtil.svgRect(svgp.getDocument(), x, y, size, size);
checkbox_box.setAttribute(SVGConstants.SVG_FILL_ATTRIBUTE, "#d4e4f1");
checkbox_box.setAttribute(SVGConstants.SVG_STROKE_ATTRIBUTE, "#a0a0a0");
checkbox_box.setAttribute(SVGConstants.SVG_STROKE_WIDTH_ATTRIBUTE, "0.5");
// create checkbox
final Element checkbox = svgp.svgElement(SVGConstants.SVG_G_TAG);
checkbox.appendChild(checkbox_box);
checkbox.appendChild(checkmark);
// create Label
if(label != null) {
Element labele = svgp.svgText(x + 2 * size, y + size, label);
// TODO: font size!
checkbox.appendChild(labele);
}
// add click event listener
EventTarget targ = (EventTarget) checkbox;
targ.addEventListener(SVGConstants.SVG_CLICK_EVENT_TYPE, new EventListener() {
/**
* Set the checkmark, and fire the event.
*/
protected void check() {
checkmark.removeAttribute(SVGConstants.SVG_STYLE_ATTRIBUTE);
checked = true;
fireSwitchEvent(new ChangeEvent(SVGCheckbox.this));
}
/**
* Remove the checkmark and fire the event.
*/
protected void uncheck() {
checkmark.setAttribute(SVGConstants.SVG_STYLE_ATTRIBUTE, SVGConstants.CSS_DISPLAY_PROPERTY + ":" + SVGConstants.CSS_NONE_VALUE);
checked = false;
fireSwitchEvent(new ChangeEvent(SVGCheckbox.this));
}
@Override
public void handleEvent(Event evt) {
if(checked) {
uncheck();
}
else {
check();
}
}
}, false);
return checkbox;
}
/**
* Register a listener for this checkbox.
*
* @param listener Listener to add
*/
public void addCheckBoxListener(ChangeListener listener) {
listenerList.add(ChangeListener.class, listener);
}
/**
* Remove a listener for this checkbox.
*
* @param listener Listener to remove
*/
public void removeCheckBoxListener(ChangeListener listener) {
listenerList.remove(ChangeListener.class, listener);
}
/**
* Return the checkmark status.
*
* @return true, when checked
*/
public boolean isChecked() {
return checked;
}
/**
* Fire the event to listeners
*
* @param evt Event to fire
*/
protected void fireSwitchEvent(ChangeEvent evt) {
Object[] listeners = listenerList.getListenerList();
for(int i = 0; i < listeners.length; i += 2) {
if(listeners[i] == ChangeListener.class) {
((ChangeListener) listeners[i + 1]).stateChanged(evt);
}
}
}
} SVGCloneVisible.java 0000664 0000000 0000000 00000003570 12657057427 0034422 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/svg package de.lmu.ifi.dbs.elki.visualization.svg;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import de.lmu.ifi.dbs.elki.utilities.xml.DOMCloner;
/**
* Clone visible parts of an SVG document.
*
* @author Erich Schubert
* @since 0.2
*/
public class SVGCloneVisible extends DOMCloner {
@Override
public Node cloneNode(Document doc, Node eold) {
// Skip elements with visibility=hidden
if(eold instanceof Element) {
Element eeold = (Element) eold;
String vis = eeold.getAttribute(SVGConstants.CSS_VISIBILITY_PROPERTY);
if(SVGConstants.CSS_HIDDEN_VALUE.equals(vis)) {
return null;
}
}
// Perform clone flat
Node enew = doc.importNode(eold, false);
// Recurse:
for(Node n = eold.getFirstChild(); n != null; n = n.getNextSibling()) {
final Node clone = cloneNode(doc, n);
if (clone != null) {
enew.appendChild(clone);
}
}
return enew;
}
}
SVGEffects.java 0000664 0000000 0000000 00000013462 12657057427 0033424 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/svg package de.lmu.ifi.dbs.elki.visualization.svg;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
/**
* Class containing some popular SVG effects.
*
* @author Erich Schubert
* @since 0.5.0
*/
public class SVGEffects {
/**
* ID for the drop shadow effect
*/
public static final String SHADOW_ID = "shadow-effect";
/**
* ID for the light gradient fill
*/
public static final String LIGHT_GRADIENT_ID = "light-gradient";
/**
* Static method to prepare a SVG document for drop shadow effects.
*
* Invoke this from an appropriate update thread!
*
* @param svgp Plot to prepare
*/
public static void addShadowFilter(SVGPlot svgp) {
Element shadow = svgp.getIdElement(SHADOW_ID);
if(shadow == null) {
shadow = svgp.svgElement(SVGConstants.SVG_FILTER_TAG);
shadow.setAttribute(SVGConstants.SVG_ID_ATTRIBUTE, SHADOW_ID);
shadow.setAttribute(SVGConstants.SVG_WIDTH_ATTRIBUTE, "140%");
shadow.setAttribute(SVGConstants.SVG_HEIGHT_ATTRIBUTE, "140%");
Element offset = svgp.svgElement(SVGConstants.SVG_FE_OFFSET_TAG);
offset.setAttribute(SVGConstants.SVG_IN_ATTRIBUTE, SVGConstants.SVG_SOURCE_ALPHA_VALUE);
offset.setAttribute(SVGConstants.SVG_RESULT_ATTRIBUTE, "off");
offset.setAttribute(SVGConstants.SVG_DX_ATTRIBUTE, "0.1");
offset.setAttribute(SVGConstants.SVG_DY_ATTRIBUTE, "0.1");
shadow.appendChild(offset);
Element gauss = svgp.svgElement(SVGConstants.SVG_FE_GAUSSIAN_BLUR_TAG);
gauss.setAttribute(SVGConstants.SVG_IN_ATTRIBUTE, "off");
gauss.setAttribute(SVGConstants.SVG_RESULT_ATTRIBUTE, "blur");
gauss.setAttribute(SVGConstants.SVG_STD_DEVIATION_ATTRIBUTE, "0.1");
shadow.appendChild(gauss);
Element blend = svgp.svgElement(SVGConstants.SVG_FE_BLEND_TAG);
blend.setAttribute(SVGConstants.SVG_IN_ATTRIBUTE, SVGConstants.SVG_SOURCE_GRAPHIC_VALUE);
blend.setAttribute(SVGConstants.SVG_IN2_ATTRIBUTE, "blur");
blend.setAttribute(SVGConstants.SVG_MODE_ATTRIBUTE, SVGConstants.SVG_NORMAL_VALUE);
shadow.appendChild(blend);
svgp.getDefs().appendChild(shadow);
svgp.putIdElement(SHADOW_ID, shadow);
}
}
/**
* Static method to prepare a SVG document for light gradient effects.
*
* Invoke this from an appropriate update thread!
*
* @param svgp Plot to prepare
*/
public static void addLightGradient(SVGPlot svgp) {
Element gradient = svgp.getIdElement(LIGHT_GRADIENT_ID);
if(gradient == null) {
gradient = svgp.svgElement(SVGConstants.SVG_LINEAR_GRADIENT_TAG);
gradient.setAttribute(SVGConstants.SVG_ID_ATTRIBUTE, LIGHT_GRADIENT_ID);
gradient.setAttribute(SVGConstants.SVG_X1_ATTRIBUTE, "0");
gradient.setAttribute(SVGConstants.SVG_Y1_ATTRIBUTE, "0");
gradient.setAttribute(SVGConstants.SVG_X2_ATTRIBUTE, "0");
gradient.setAttribute(SVGConstants.SVG_Y2_ATTRIBUTE, "1");
Element stop0 = svgp.svgElement(SVGConstants.SVG_STOP_TAG);
stop0.setAttribute(SVGConstants.SVG_STOP_COLOR_ATTRIBUTE, "white");
stop0.setAttribute(SVGConstants.SVG_STOP_OPACITY_ATTRIBUTE, "1");
stop0.setAttribute(SVGConstants.SVG_OFFSET_ATTRIBUTE, "0");
gradient.appendChild(stop0);
Element stop04 = svgp.svgElement(SVGConstants.SVG_STOP_TAG);
stop04.setAttribute(SVGConstants.SVG_STOP_COLOR_ATTRIBUTE, "white");
stop04.setAttribute(SVGConstants.SVG_STOP_OPACITY_ATTRIBUTE, "0");
stop04.setAttribute(SVGConstants.SVG_OFFSET_ATTRIBUTE, ".4");
gradient.appendChild(stop04);
Element stop06 = svgp.svgElement(SVGConstants.SVG_STOP_TAG);
stop06.setAttribute(SVGConstants.SVG_STOP_COLOR_ATTRIBUTE, "black");
stop06.setAttribute(SVGConstants.SVG_STOP_OPACITY_ATTRIBUTE, "0");
stop06.setAttribute(SVGConstants.SVG_OFFSET_ATTRIBUTE, ".6");
gradient.appendChild(stop06);
Element stop1 = svgp.svgElement(SVGConstants.SVG_STOP_TAG);
stop1.setAttribute(SVGConstants.SVG_STOP_COLOR_ATTRIBUTE, "black");
stop1.setAttribute(SVGConstants.SVG_STOP_OPACITY_ATTRIBUTE, ".5");
stop1.setAttribute(SVGConstants.SVG_OFFSET_ATTRIBUTE, "1");
gradient.appendChild(stop1);
svgp.getDefs().appendChild(gradient);
svgp.putIdElement(LIGHT_GRADIENT_ID, gradient);
}
}
/**
* Checkmark path, sized approx. 15x15
*/
public static final String SVG_CHECKMARK_PATH = "M0 6.458 L2.047 4.426 5.442 7.721 12.795 0 15 2.117 5.66 11.922 Z";
/**
* Creates a 15x15 big checkmark
*
* @param svgp Plot to create the element for
* @return Element
*/
public static Element makeCheckmark(SVGPlot svgp) {
Element checkmark = svgp.svgElement(SVGConstants.SVG_PATH_TAG);
checkmark.setAttribute(SVGConstants.SVG_D_ATTRIBUTE, SVG_CHECKMARK_PATH);
checkmark.setAttribute(SVGConstants.SVG_FILL_ATTRIBUTE, SVGConstants.CSS_BLACK_VALUE);
checkmark.setAttribute(SVGConstants.SVG_STROKE_ATTRIBUTE, SVGConstants.CSS_NONE_VALUE);
return checkmark;
}
} SVGHyperCube.java 0000664 0000000 0000000 00000025617 12657057427 0033740 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/svg package de.lmu.ifi.dbs.elki.visualization.svg;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.ArrayList;
import java.util.List;
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable;
import de.lmu.ifi.dbs.elki.math.linearalgebra.VMath;
import de.lmu.ifi.dbs.elki.utilities.BitsUtil;
import de.lmu.ifi.dbs.elki.visualization.projections.Projection2D;
/**
* Utility class to draw hypercubes, wireframe and filled.
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.uses SVGPath
* @apiviz.uses Projection2D
*/
public class SVGHyperCube {
/**
* Wireframe hypercube.
*
* @param svgp SVG Plot
* @param proj Visualization projection
* @param min First corner
* @param max Opposite corner
* @return path element
*/
public static Element drawFrame(SVGPlot svgp, Projection2D proj, double[] min, double[] max) {
SVGPath path = new SVGPath();
ArrayList edges = getVisibleEdges(proj, min, max);
double[] rv_min = proj.fastProjectDataToRenderSpace(min);
recDrawEdges(path, rv_min[0], rv_min[1], edges, 0, BitsUtil.zero(edges.size()));
return path.makeElement(svgp);
}
/**
* Wireframe hypercube.
*
* @param svgp SVG Plot
* @param proj Visualization projection
* @param min First corner
* @param max Opposite corner
* @return path element
*/
public static Element drawFrame(SVGPlot svgp, Projection2D proj, NumberVector min, NumberVector max) {
SVGPath path = new SVGPath();
ArrayList edges = getVisibleEdges(proj, min, max);
double[] rv_min = proj.fastProjectDataToRenderSpace(min);
recDrawEdges(path, rv_min[0], rv_min[1], edges, 0, BitsUtil.zero(edges.size()));
return path.makeElement(svgp);
}
/**
* Wireframe hypercube.
*
* @param svgp SVG Plot
* @param proj Visualization projection
* @param box Bounding box
* @return path element
*/
public static Element drawFrame(SVGPlot svgp, Projection2D proj, SpatialComparable box) {
SVGPath path = new SVGPath();
ArrayList edges = getVisibleEdges(proj, box);
final int dim = box.getDimensionality();
double[] min = new double[dim];
for(int i = 0; i < dim; i++) {
min[i] = box.getMin(i);
}
double[] rv_min = proj.fastProjectDataToRenderSpace(min);
recDrawEdges(path, rv_min[0], rv_min[1], edges, 0, BitsUtil.zero(edges.size()));
return path.makeElement(svgp);
}
/**
* Filled hypercube.
*
* @param svgp SVG Plot
* @param cls CSS class to use.
* @param proj Visualization projection
* @param min First corner
* @param max Opposite corner
* @return group element
*/
public static Element drawFilled(SVGPlot svgp, String cls, Projection2D proj, double[] min, double[] max) {
Element group = svgp.svgElement(SVGConstants.SVG_G_TAG);
ArrayList edges = getVisibleEdges(proj, min, max);
double[] rv_min = proj.fastProjectDataToRenderSpace(min);
recDrawSides(svgp, group, cls, rv_min[0], rv_min[1], edges, 0, BitsUtil.zero(edges.size()));
return group;
}
/**
* Filled hypercube.
*
* @param svgp SVG Plot
* @param cls CSS class to use.
* @param proj Visualization projection
* @param min First corner
* @param max Opposite corner
* @return group element
*/
public static Element drawFilled(SVGPlot svgp, String cls, Projection2D proj, NumberVector min, NumberVector max) {
Element group = svgp.svgElement(SVGConstants.SVG_G_TAG);
ArrayList edges = getVisibleEdges(proj, min, max);
double[] rv_min = proj.fastProjectDataToRenderSpace(min);
recDrawSides(svgp, group, cls, rv_min[0], rv_min[1], edges, 0, BitsUtil.zero(edges.size()));
return group;
}
/**
* Filled hypercube.
*
* @param svgp SVG Plot
* @param cls CSS class to use.
* @param proj Visualization projection
* @param box Bounding box
* @return group element
*/
public static Element drawFilled(SVGPlot svgp, String cls, Projection2D proj, SpatialComparable box) {
Element group = svgp.svgElement(SVGConstants.SVG_G_TAG);
ArrayList edges = getVisibleEdges(proj, box);
final int dim = box.getDimensionality();
double[] min = new double[dim];
for(int i = 0; i < dim; i++) {
min[i] = box.getMin(i);
}
double[] rv_min = proj.fastProjectDataToRenderSpace(min);
recDrawSides(svgp, group, cls, rv_min[0], rv_min[1], edges, 0, BitsUtil.zero(edges.size()));
return group;
}
/**
* Get the visible (non-0) edges of a hypercube
*
* @param proj Projection
* @param s_min Minimum value (in data space)
* @param s_max Maximum value (in data space)
* @return Edge list
*/
private static ArrayList getVisibleEdges(Projection2D proj, double[] s_min, double[] s_max) {
final int dim = s_min.length;
double[] s_deltas = VMath.minus(s_max, s_min);
ArrayList r_edges = new ArrayList<>(dim);
for(int i = 0; i < dim; i++) {
double[] delta = new double[dim];
delta[i] = s_deltas[i];
double[] deltas = proj.fastProjectRelativeDataToRenderSpace(delta);
if(deltas[0] != 0 || deltas[1] != 0) {
r_edges.add(deltas);
}
}
return r_edges;
}
/**
* Get the visible (non-0) edges of a hypercube
*
* @param proj Projection
* @param s_min Minimum value (in data space)
* @param s_max Maximum value (in data space)
* @return Edge list
*/
private static ArrayList getVisibleEdges(Projection2D proj, NumberVector s_min, NumberVector s_max) {
final int dim = s_min.getDimensionality();
double[] s_deltas = new double[dim];
for(int i = 0; i < dim; i++) {
s_deltas[i] = s_max.doubleValue(i) - s_min.doubleValue(i);
}
ArrayList r_edges = new ArrayList<>(dim);
for(int i = 0; i < dim; i++) {
double[] delta = new double[dim];
delta[i] = s_deltas[i];
double[] deltas = proj.fastProjectRelativeDataToRenderSpace(delta);
if(deltas[0] != 0 || deltas[1] != 0) {
r_edges.add(deltas);
}
}
return r_edges;
}
/**
* Get the visible (non-0) edges of a hypercube
*
* @param proj Projection
* @param box Box object
* @return Edge list
*/
private static ArrayList getVisibleEdges(Projection2D proj, SpatialComparable box) {
final int dim = box.getDimensionality();
double[] s_deltas = new double[dim];
for(int i = 0; i < dim; i++) {
s_deltas[i] = box.getMax(i) - box.getMin(i);
}
ArrayList r_edges = new ArrayList<>(dim);
for(int i = 0; i < dim; i++) {
double[] delta = new double[dim];
delta[i] = s_deltas[i];
double[] deltas = proj.fastProjectRelativeDataToRenderSpace(delta);
if(deltas[0] != 0 || deltas[1] != 0) {
r_edges.add(deltas);
}
}
return r_edges;
}
/**
* Recursive helper for hypercube drawing.
*
* @param path path
* @param minx starting corner
* @param miny starting corner
* @param r_edges edge vectors
* @param off recursion offset (to avoid multi-recursion)
* @param b bit set of drawn edges
*/
private static void recDrawEdges(SVGPath path, double minx, double miny, List r_edges, int off, long[] b) {
// Draw all "missing" edges
for(int i = 0; i < r_edges.size(); i++) {
if(BitsUtil.get(b, i)) {
continue;
}
final double[] edge = r_edges.get(i);
final double x_i = minx + edge[0];
if(!isFinite(x_i)) {
continue;
}
final double y_i = miny + edge[1];
if(!isFinite(y_i)) {
continue;
}
path.moveTo(minx, miny);
path.drawTo(x_i, y_i);
// Recursion
BitsUtil.setI(b, i);
recDrawEdges(path, x_i, y_i , r_edges, i + 1, b);
BitsUtil.clearI(b, i);
}
}
/**
* Recursive helper for hypercube drawing.
*
* @param plot Plot
* @param group Group element
* @param cls CSS class
* @param minx starting corner
* @param miny starting corner
* @param r_edges edge vectors
* @param off recursion offset (to avoid multi-recursion)
* @param b bit set of drawn edges
*/
private static void recDrawSides(SVGPlot plot, Element group, String cls, double minx, double miny, List r_edges, int off, long[] b) {
StringBuilder pbuf = new StringBuilder();
// Draw all "missing" sides
for(int i = 0; i < r_edges.size() - 1; i++) {
if(BitsUtil.get(b, i)) {
continue;
}
double[] deltai = r_edges.get(i);
final double xi = minx + deltai[0];
if(!isFinite(xi)) {
continue;
}
final double yi = miny + deltai[1];
if(!isFinite(yi)) {
continue;
}
for(int j = i + 1; j < r_edges.size(); j++) {
if(BitsUtil.get(b, j)) {
continue;
}
double[] deltaj = r_edges.get(j);
final double dxj = deltaj[0];
if(!isFinite(xi)) {
continue;
}
final double dyj = deltaj[1];
if(!isFinite(dxj)) {
continue;
}
pbuf.delete(0, pbuf.length()); // Clear
pbuf.append(SVGUtil.fmt(minx)).append(',');
pbuf.append(SVGUtil.fmt(miny)).append(' ');
pbuf.append(SVGUtil.fmt(xi)).append(',');
pbuf.append(SVGUtil.fmt(yi)).append(' ');
pbuf.append(SVGUtil.fmt(xi + dxj)).append(',');
pbuf.append(SVGUtil.fmt(yi + dyj)).append(' ');
pbuf.append(SVGUtil.fmt(minx + dxj)).append(',');
pbuf.append(SVGUtil.fmt(miny + dyj));
Element poly = plot.svgElement(SVGConstants.SVG_POLYGON_TAG);
SVGUtil.setAtt(poly, SVGConstants.SVG_POINTS_ATTRIBUTE, pbuf.toString());
SVGUtil.setCSSClass(poly, cls);
group.appendChild(poly);
}
// Recursion
BitsUtil.setI(b, i);
recDrawSides(plot, group, cls, xi, yi, r_edges, i + 1, b);
BitsUtil.clearI(b, i);
}
}
/**
* Finite (and not NaN) double values.
*
* @param v Value
* @return true, when finite.
*/
private static boolean isFinite(double v) {
return v < Double.POSITIVE_INFINITY && v > Double.NEGATIVE_INFINITY;
}
} SVGHyperSphere.java 0000664 0000000 0000000 00000026202 12657057427 0034277 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/svg package de.lmu.ifi.dbs.elki.visualization.svg;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.w3c.dom.Element;
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.utilities.BitsUtil;
import de.lmu.ifi.dbs.elki.visualization.projections.Projection2D;
/**
* Utility class to draw hypercubes, wireframe and filled.
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.uses SVGPath
* @apiviz.uses Projection2D
*/
public class SVGHyperSphere {
/**
* Factor used for approximating circles with cubic beziers.
*
* kappa = 4 * (Math.sqrt(2)-1)/3
*/
public static final double EUCLIDEAN_KAPPA = 0.5522847498;
/**
* Wireframe "manhattan" hypersphere
*
* @param svgp SVG Plot
* @param proj Visualization projection
* @param mid mean vector
* @param radius radius
* @return path element
*/
public static Element drawManhattan(SVGPlot svgp, Projection2D proj, NumberVector mid, double radius) {
final double[] v_mid = mid.getColumnVector().getArrayRef(); // a copy
final long[] dims = proj.getVisibleDimensions2D();
SVGPath path = new SVGPath();
for(int dim = BitsUtil.nextSetBit(dims, 0); dim >= 0; dim = BitsUtil.nextSetBit(dims, dim + 1)) {
v_mid[dim] += radius;
double[] p1 = proj.fastProjectDataToRenderSpace(v_mid);
v_mid[dim] -= radius;
v_mid[dim] -= radius;
double[] p2 = proj.fastProjectDataToRenderSpace(v_mid);
v_mid[dim] += radius;
for(int dim2 = BitsUtil.nextSetBit(dims, 0); dim2 >= 0; dim2 = BitsUtil.nextSetBit(dims, dim2 + 1)) {
if(dim < dim2) {
v_mid[dim2] += radius;
double[] p3 = proj.fastProjectDataToRenderSpace(v_mid);
v_mid[dim2] -= radius;
v_mid[dim2] -= radius;
double[] p4 = proj.fastProjectDataToRenderSpace(v_mid);
v_mid[dim2] += radius;
path.moveTo(p1[0], p1[1]);
path.drawTo(p3[0], p3[1]);
path.moveTo(p1[0], p1[1]);
path.drawTo(p4[0], p4[1]);
path.moveTo(p2[0], p2[1]);
path.drawTo(p3[0], p3[1]);
path.moveTo(p2[0], p2[1]);
path.drawTo(p4[0], p4[1]);
path.close();
}
}
}
return path.makeElement(svgp);
}
/**
* Wireframe "euclidean" hypersphere
*
* @param svgp SVG Plot
* @param proj Visualization projection
* @param mid mean vector
* @param radius radius
* @return path element
*/
public static Element drawEuclidean(SVGPlot svgp, Projection2D proj, NumberVector mid, double radius) {
double[] v_mid = mid.getColumnVector().getArrayRef(); // a copy
long[] dims = proj.getVisibleDimensions2D();
SVGPath path = new SVGPath();
for(int dim = BitsUtil.nextSetBit(dims, 0); dim >= 0; dim = BitsUtil.nextSetBit(dims, dim + 1)) {
v_mid[dim] += radius;
double[] p1 = proj.fastProjectDataToRenderSpace(v_mid);
v_mid[dim] -= radius;
v_mid[dim] -= radius;
double[] p2 = proj.fastProjectDataToRenderSpace(v_mid);
v_mid[dim] += radius;
// delta vector
double[] dt1 = new double[v_mid.length];
dt1[dim] = radius;
double[] d1 = proj.fastProjectRelativeDataToRenderSpace(dt1);
for(int dim2 = BitsUtil.nextSetBit(dims, 0); dim2 >= 0; dim2 = BitsUtil.nextSetBit(dims, dim2 + 1)) {
if(dim < dim2) {
v_mid[dim2] += radius;
double[] p3 = proj.fastProjectDataToRenderSpace(v_mid);
v_mid[dim2] -= radius;
v_mid[dim2] -= radius;
double[] p4 = proj.fastProjectDataToRenderSpace(v_mid);
v_mid[dim2] += radius;
// delta vector
double[] dt2 = new double[v_mid.length];
dt2[dim2] = radius;
double[] d2 = proj.fastProjectRelativeDataToRenderSpace(dt2);
path.moveTo(p1[0], p1[1]);
path.cubicTo(p1[0] + d2[0] * EUCLIDEAN_KAPPA, p1[1] + d2[1] * EUCLIDEAN_KAPPA, p3[0] + d1[0] * EUCLIDEAN_KAPPA, p3[1] + d1[1] * EUCLIDEAN_KAPPA, p3[0], p3[1]);
path.cubicTo(p3[0] - d1[0] * EUCLIDEAN_KAPPA, p3[1] - d1[1] * EUCLIDEAN_KAPPA, p2[0] + d2[0] * EUCLIDEAN_KAPPA, p2[1] + d2[1] * EUCLIDEAN_KAPPA, p2[0], p2[1]);
path.cubicTo(p2[0] - d2[0] * EUCLIDEAN_KAPPA, p2[1] - d2[1] * EUCLIDEAN_KAPPA, p4[0] - d1[0] * EUCLIDEAN_KAPPA, p4[1] - d1[1] * EUCLIDEAN_KAPPA, p4[0], p4[1]);
path.cubicTo(p4[0] + d1[0] * EUCLIDEAN_KAPPA, p4[1] + d1[1] * EUCLIDEAN_KAPPA, p1[0] - d2[0] * EUCLIDEAN_KAPPA, p1[1] - d2[1] * EUCLIDEAN_KAPPA, p1[0], p1[1]);
path.close();
}
}
}
return path.makeElement(svgp);
}
/**
* Wireframe "Lp" hypersphere
*
* @param svgp SVG Plot
* @param proj Visualization projection
* @param mid mean vector
* @param radius radius
* @param p L_p value
* @return path element
*/
public static Element drawLp(SVGPlot svgp, Projection2D proj, NumberVector mid, double radius, double p) {
final double[] v_mid = mid.getColumnVector().getArrayRef();
final long[] dims = proj.getVisibleDimensions2D();
final double kappax, kappay;
if(p > 1.) {
final double kappal = Math.pow(0.5, 1. / p);
kappax = Math.min(1.3, 4. * (2 * kappal - 1) / 3.);
kappay = 0;
}
else if(p < 1.) {
final double kappal = 1 - Math.pow(0.5, 1. / p);
kappax = 0;
kappay = Math.min(1.3, 4. * (2 * kappal - 1) / 3.);
}
else {
kappax = 0;
kappay = 0;
}
// LoggingUtil.warning("kappax: " + kappax + " kappay: " + kappay);
SVGPath path = new SVGPath();
for(int dim = BitsUtil.nextSetBit(dims, 0); dim >= 0; dim = BitsUtil.nextSetBit(dims, dim + 1)) {
v_mid[dim] += radius;
double[] pvp0 = proj.fastProjectDataToRenderSpace(v_mid);
v_mid[dim] -= radius;
v_mid[dim] -= radius;
double[] pvm0 = proj.fastProjectDataToRenderSpace(v_mid);
v_mid[dim] += radius;
// delta vector
double[] tvd0 = new double[v_mid.length];
tvd0[dim] = radius;
double[] vd0 = proj.fastProjectRelativeDataToRenderSpace(tvd0);
for(int dim2 = BitsUtil.nextSetBit(dims, 0); dim2 >= 0; dim2 = BitsUtil.nextSetBit(dims, dim2 + 1)) {
if(dim < dim2) {
v_mid[dim2] += radius;
double[] pv0p = proj.fastProjectDataToRenderSpace(v_mid);
v_mid[dim2] -= radius;
v_mid[dim2] -= radius;
double[] pv0m = proj.fastProjectDataToRenderSpace(v_mid);
v_mid[dim2] += radius;
// delta vector
double[] tv0d = new double[v_mid.length];
tv0d[dim2] = radius;
double[] v0d = proj.fastProjectRelativeDataToRenderSpace(tv0d);
if(p > 1) {
// p > 1
path.moveTo(pvp0[0], pvp0[1]);
// support points, p0 to 0p
final double s_pp1_x = pvp0[0] + v0d[0] * kappax;
final double s_pp1_y = pvp0[1] + v0d[1] * kappax;
final double s_pp2_x = pv0p[0] + vd0[0] * kappax;
final double s_pp2_y = pv0p[1] + vd0[1] * kappax;
path.cubicTo(s_pp1_x, s_pp1_y, s_pp2_x, s_pp2_y, pv0p[0], pv0p[1]);
// support points, 0p to m0
final double s_mp1_x = pv0p[0] - vd0[0] * kappax;
final double s_mp1_y = pv0p[1] - vd0[1] * kappax;
final double s_mp2_x = pvm0[0] + v0d[0] * kappax;
final double s_mp2_y = pvm0[1] + v0d[1] * kappax;
path.cubicTo(s_mp1_x, s_mp1_y, s_mp2_x, s_mp2_y, pvm0[0], pvm0[1]);
// support points, m0 to 0m
final double s_mm1_x = pvm0[0] - v0d[0] * kappax;
final double s_mm1_y = pvm0[1] - v0d[1] * kappax;
final double s_mm2_x = pv0m[0] - vd0[0] * kappax;
final double s_mm2_y = pv0m[1] - vd0[1] * kappax;
path.cubicTo(s_mm1_x, s_mm1_y, s_mm2_x, s_mm2_y, pv0m[0], pv0m[1]);
// support points, 0m to p0
final double s_pm1_x = pv0m[0] + vd0[0] * kappax;
final double s_pm1_y = pv0m[1] + vd0[1] * kappax;
final double s_pm2_x = pvp0[0] - v0d[0] * kappax;
final double s_pm2_y = pvp0[1] - v0d[1] * kappax;
path.cubicTo(s_pm1_x, s_pm1_y, s_pm2_x, s_pm2_y, pvp0[0], pvp0[1]);
path.close();
}
else if(p < 1) {
// p < 1
// support points, p0 to 0p
final double s_vp0_x = pvp0[0] - vd0[0] * kappay;
final double s_vp0_y = pvp0[1] - vd0[1] * kappay;
final double s_v0p_x = pv0p[0] - v0d[0] * kappay;
final double s_v0p_y = pv0p[1] - v0d[1] * kappay;
final double s_vm0_x = pvm0[0] + vd0[0] * kappay;
final double s_vm0_y = pvm0[1] + vd0[1] * kappay;
final double s_v0m_x = pv0m[0] + v0d[0] * kappay;
final double s_v0m_y = pv0m[1] + v0d[1] * kappay;
// Draw the star
path.moveTo(pvp0[0], pvp0[1]);
path.cubicTo(s_vp0_x, s_vp0_y, s_v0p_x, s_v0p_y, pv0p[0], pv0p[1]);
path.cubicTo(s_v0p_x, s_v0p_y, s_vm0_x, s_vm0_y, pvm0[0], pvm0[1]);
path.cubicTo(s_vm0_x, s_vm0_y, s_v0m_x, s_v0m_y, pv0m[0], pv0m[1]);
path.cubicTo(s_v0m_x, s_v0m_y, s_vp0_x, s_vp0_y, pvp0[0], pvp0[1]);
path.close();
}
else {
// p == 1 - Manhattan
path.moveTo(pvp0[0], pvp0[1]);
path.lineTo(pv0p[0], pv0p[1]);
path.lineTo(pvm0[0], pvm0[1]);
path.lineTo(pv0m[0], pv0m[1]);
path.lineTo(pvp0[0], pvp0[1]);
path.close();
}
}
}
}
return path.makeElement(svgp);
}
/**
* Wireframe "cross" hypersphere
*
* @param svgp SVG Plot
* @param proj Visualization projection
* @param mid mean vector
* @param radius radius
* @return path element
*/
public static Element drawCross(SVGPlot svgp, Projection2D proj, NumberVector mid, double radius) {
final double[] v_mid = mid.getColumnVector().getArrayRef();
final long[] dims = proj.getVisibleDimensions2D();
SVGPath path = new SVGPath();
for(int dim = BitsUtil.nextSetBit(dims, 0); dim >= 0; dim = BitsUtil.nextSetBit(dims, dim + 1)) {
v_mid[dim] += radius;
double[] p1 = proj.fastProjectDataToRenderSpace(v_mid);
v_mid[dim] -= radius;
path.moveTo(p1[0], p1[1]);
v_mid[dim] -= radius;
double[] p2 = proj.fastProjectDataToRenderSpace(v_mid);
v_mid[dim] += radius;
path.drawTo(p2[0], p2[1]);
path.close();
}
return path.makeElement(svgp);
}
}
elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/svg/SVGPath.java 0000664 0000000 0000000 00000057450 12657057427 0033025 0 ustar 00root root 0000000 0000000 package de.lmu.ifi.dbs.elki.visualization.svg;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import de.lmu.ifi.dbs.elki.data.spatial.Polygon;
import de.lmu.ifi.dbs.elki.math.linearalgebra.Vector;
import de.lmu.ifi.dbs.elki.utilities.datastructures.iterator.ArrayListIter;
/**
* Element used for building an SVG path using a string buffer.
*
* @author Erich Schubert
* @since 0.3
*
* @apiviz.uses Element oneway - - «create»
*/
public class SVGPath {
/**
* String buffer for building the path.
*/
private StringBuilder buf = new StringBuilder();
/**
* The last action we did, to not add unnecessary commands
*/
private String lastaction = null;
/**
* The absolute "smooth cubic to" SVG path command (missing from
* SVGConstants).
*/
public static final String PATH_SMOOTH_CUBIC_TO = "S";
/**
* The lower case version (relative) line to command.
*/
public static final String PATH_LINE_TO_RELATIVE = SVGConstants.PATH_LINE_TO.toLowerCase();
/**
* The lower case version (relative) move command.
*/
public static final String PATH_MOVE_RELATIVE = SVGConstants.PATH_MOVE.toLowerCase();
/**
* The lower case version (relative) horizontal line to command.
*/
public static final String PATH_HORIZONTAL_LINE_TO_RELATIVE = SVGConstants.PATH_HORIZONTAL_LINE_TO.toLowerCase();
/**
* The lower case version (relative) vertical line to command.
*/
public static final String PATH_VERTICAL_LINE_TO_RELATIVE = SVGConstants.PATH_VERTICAL_LINE_TO.toLowerCase();
/**
* The lower case version (relative) cubic line to command.
*/
public static final String PATH_CUBIC_TO_RELATIVE = SVGConstants.PATH_CUBIC_TO.toLowerCase();
/**
* The lower case version (relative) smooth cubic to command.
*/
public static final String PATH_SMOOTH_CUBIC_TO_RELATIVE = PATH_SMOOTH_CUBIC_TO.toLowerCase();
/**
* The lower case version (relative) quadratic interpolation to command.
*/
public static final String PATH_QUAD_TO_RELATIVE = SVGConstants.PATH_QUAD_TO.toLowerCase();
/**
* The lower case version (relative) smooth quadratic interpolation to
* command.
*/
public static final String PATH_SMOOTH_QUAD_TO_RELATIVE = SVGConstants.PATH_SMOOTH_QUAD_TO.toLowerCase();
/**
* The lower case version (relative) path arc command.
*/
public static final String PATH_ARC_RELATIVE = SVGConstants.PATH_ARC.toLowerCase();
/**
* Empty path constructor.
*/
public SVGPath() {
// Nothing to do.
}
/**
* Constructor with initial point.
*
* @param x initial coordinates
* @param y initial coordinates
*/
public SVGPath(double x, double y) {
this();
this.moveTo(x, y);
}
/**
* Constructor with initial point.
*
* @param xy initial coordinates
*/
public SVGPath(double[] xy) {
this();
this.moveTo(xy[0], xy[1]);
}
/**
* Constructor from a vector collection (e.g. a polygon)
*
* @param vectors vectors
*/
public SVGPath(Polygon vectors) {
this();
for(ArrayListIter it = vectors.iter(); it.valid(); it.advance()) {
Vector vec = it.get();
this.drawTo(vec.doubleValue(0), vec.doubleValue(1));
}
this.close();
}
/**
* Draw a line given a series of coordinates.
*
* Helper function that will use "move" for the first point, "lineto" for the
* remaining.
*
* @param x new coordinates
* @param y new coordinates
* @return path object, for compact syntax.
*/
public SVGPath drawTo(double x, double y) {
return !isStarted() ? moveTo(x, y) : lineTo(x, y);
}
/**
* Draw a line given a series of coordinates.
*
* Helper function that will use "move" for the first point, "lineto" for the
* remaining.
*
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath drawTo(double[] xy) {
return !isStarted() ? moveTo(xy[0], xy[0]) : lineTo(xy[0], xy[1]);
}
/**
* Draw a line given a series of coordinates.
*
* Helper function that will use "move" for the first point, "lineto" for the
* remaining.
*
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath drawTo(Vector xy) {
return !isStarted() ? moveTo(xy.doubleValue(0), xy.doubleValue(1)) : lineTo(xy.doubleValue(0), xy.doubleValue(1));
}
/**
* Test whether the path drawing has already started.
*
* @return Path freshness
*/
public boolean isStarted() {
return lastaction != null;
}
/**
* Draw a line to the given coordinates.
*
* @param x new coordinates
* @param y new coordinates
* @return path object, for compact syntax.
*/
public SVGPath lineTo(double x, double y) {
if(x > Double.NEGATIVE_INFINITY && x < Double.POSITIVE_INFINITY //
&& y > Double.NEGATIVE_INFINITY && y < Double.POSITIVE_INFINITY) {
append(SVGConstants.PATH_LINE_TO, x, y);
}
return this;
}
/**
* Draw a line to the given coordinates.
*
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath lineTo(double[] xy) {
return lineTo(xy[0], xy[1]);
}
/**
* Draw a line to the given coordinates.
*
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath lineTo(Vector xy) {
return lineTo(xy.doubleValue(0), xy.doubleValue(1));
}
/**
* Draw a line to the given relative coordinates.
*
* @param x relative coordinates
* @param y relative coordinates
* @return path object, for compact syntax.
*/
public SVGPath relativeLineTo(double x, double y) {
if(x > Double.NEGATIVE_INFINITY && x < Double.POSITIVE_INFINITY //
&& y > Double.NEGATIVE_INFINITY && y < Double.POSITIVE_INFINITY) {
append(PATH_LINE_TO_RELATIVE, x, y);
}
return this;
}
/**
* Draw a line to the given relative coordinates.
*
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath relativeLineTo(double[] xy) {
return relativeLineTo(xy[0], xy[1]);
}
/**
* Draw a line to the given relative coordinates.
*
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath relativeLineTo(Vector xy) {
return relativeLineTo(xy.doubleValue(0), xy.doubleValue(1));
}
/**
* Draw a horizontal line to the given x coordinate.
*
* @param x new coordinates
* @return path object, for compact syntax.
*/
public SVGPath horizontalLineTo(double x) {
if(x > Double.NEGATIVE_INFINITY && x < Double.POSITIVE_INFINITY) {
append(SVGConstants.PATH_HORIZONTAL_LINE_TO, x);
}
return this;
}
/**
* Draw a horizontal line to the given relative x coordinate.
*
* @param x new coordinates
* @return path object, for compact syntax.
*/
public SVGPath relativeHorizontalLineTo(double x) {
if(x > Double.NEGATIVE_INFINITY && x < Double.POSITIVE_INFINITY) {
append(PATH_HORIZONTAL_LINE_TO_RELATIVE, x);
}
return this;
}
/**
* Draw a vertical line to the given y coordinate.
*
* @param y new coordinate
* @return path object, for compact syntax.
*/
public SVGPath verticalLineTo(double y) {
if(y > Double.NEGATIVE_INFINITY && y < Double.POSITIVE_INFINITY) {
append(SVGConstants.PATH_VERTICAL_LINE_TO, y);
}
return this;
}
/**
* Draw a vertical line to the given relative y coordinate.
*
* @param y new coordinate
* @return path object, for compact syntax.
*/
public SVGPath relativeVerticalLineTo(double y) {
if(y > Double.NEGATIVE_INFINITY && y < Double.POSITIVE_INFINITY) {
append(PATH_VERTICAL_LINE_TO_RELATIVE, y);
}
return this;
}
/**
* Move to the given coordinates.
*
* @param x new coordinates
* @param y new coordinates
* @return path object, for compact syntax.
*/
public SVGPath moveTo(double x, double y) {
if(x > Double.NEGATIVE_INFINITY && x < Double.POSITIVE_INFINITY //
&& y > Double.NEGATIVE_INFINITY && y < Double.POSITIVE_INFINITY) {
append(SVGConstants.PATH_MOVE, x, y);
}
return this;
}
/**
* Move to the given coordinates.
*
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath moveTo(double[] xy) {
return moveTo(xy[0], xy[1]);
}
/**
* Move to the given coordinates.
*
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath moveTo(Vector xy) {
return moveTo(xy.doubleValue(0), xy.doubleValue(1));
}
/**
* Move to the given relative coordinates.
*
* @param x new coordinates
* @param y new coordinates
* @return path object, for compact syntax.
*/
public SVGPath relativeMoveTo(double x, double y) {
if(x > Double.NEGATIVE_INFINITY && x < Double.POSITIVE_INFINITY //
&& y > Double.NEGATIVE_INFINITY && y < Double.POSITIVE_INFINITY) {
append(PATH_MOVE_RELATIVE, x, y);
}
return this;
}
/**
* Move to the given relative coordinates.
*
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath relativeMoveTo(double[] xy) {
return relativeMoveTo(xy[0], xy[1]);
}
/**
* Move to the given relative coordinates.
*
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath relativeMoveTo(Vector xy) {
return relativeMoveTo(xy.doubleValue(0), xy.doubleValue(1));
}
/**
* Cubic Bezier line to the given coordinates.
*
* @param c1x first control point x
* @param c1y first control point y
* @param c2x second control point x
* @param c2y second control point y
* @param x new coordinates
* @param y new coordinates
* @return path object, for compact syntax.
*/
public SVGPath cubicTo(double c1x, double c1y, double c2x, double c2y, double x, double y) {
append(SVGConstants.PATH_CUBIC_TO, c1x, c1y, c2x, c2y, x, y);
return this;
}
/**
* Cubic Bezier line to the given coordinates.
*
* @param c1xy first control point
* @param c2xy second control point
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath cubicTo(double[] c1xy, double[] c2xy, double[] xy) {
append(SVGConstants.PATH_CUBIC_TO, c1xy[0], c1xy[1], c2xy[0], c2xy[1], xy[0], xy[1]);
return this;
}
/**
* Cubic Bezier line to the given coordinates.
*
* @param c1xy first control point
* @param c2xy second control point
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath cubicTo(Vector c1xy, Vector c2xy, Vector xy) {
append(SVGConstants.PATH_CUBIC_TO, c1xy.doubleValue(0), c1xy.doubleValue(1), c2xy.doubleValue(0), c2xy.doubleValue(1), xy.doubleValue(0), xy.doubleValue(1));
return this;
}
/**
* Cubic Bezier line to the given relative coordinates.
*
* @param c1x first control point x
* @param c1y first control point y
* @param c2x second control point x
* @param c2y second control point y
* @param x new coordinates
* @param y new coordinates
* @return path object, for compact syntax.
*/
public SVGPath relativeCubicTo(double c1x, double c1y, double c2x, double c2y, double x, double y) {
append(PATH_CUBIC_TO_RELATIVE, c1x, c1y, c2x, c2y, x, y);
return this;
}
/**
* Cubic Bezier line to the given relative coordinates.
*
* @param c1xy first control point
* @param c2xy second control point
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath relativeCubicTo(double[] c1xy, double[] c2xy, double[] xy) {
append(PATH_CUBIC_TO_RELATIVE, c1xy[0], c1xy[1], c2xy[0], c2xy[1], xy[0], xy[1]);
return this;
}
/**
* Cubic Bezier line to the given relative coordinates.
*
* @param c1xy first control point
* @param c2xy second control point
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath relativeCubicTo(Vector c1xy, Vector c2xy, Vector xy) {
append(PATH_CUBIC_TO_RELATIVE, c1xy.doubleValue(0), c1xy.doubleValue(1), c2xy.doubleValue(0), c2xy.doubleValue(1), xy.doubleValue(0), xy.doubleValue(1));
return this;
}
/**
* Smooth Cubic Bezier line to the given coordinates.
*
* @param c2x second control point x
* @param c2y second control point y
* @param x new coordinates
* @param y new coordinates
* @return path object, for compact syntax.
*/
public SVGPath smoothCubicTo(double c2x, double c2y, double x, double y) {
append(PATH_SMOOTH_CUBIC_TO, c2x, c2y, x, y);
return this;
}
/**
* Smooth Cubic Bezier line to the given coordinates.
*
* @param c2xy second control point
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath smoothCubicTo(double[] c2xy, double[] xy) {
append(PATH_SMOOTH_CUBIC_TO, c2xy[0], c2xy[1], xy[0], xy[1]);
return this;
}
/**
* Smooth Cubic Bezier line to the given coordinates.
*
* @param c2xy second control point
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath smoothCubicTo(Vector c2xy, Vector xy) {
append(PATH_SMOOTH_CUBIC_TO, c2xy.doubleValue(0), c2xy.doubleValue(1), xy.doubleValue(0), xy.doubleValue(1));
return this;
}
/**
* Smooth Cubic Bezier line to the given relative coordinates.
*
* @param c2x second control point x
* @param c2y second control point y
* @param x new coordinates
* @param y new coordinates
* @return path object, for compact syntax.
*/
public SVGPath relativeSmoothCubicTo(double c2x, double c2y, double x, double y) {
append(PATH_SMOOTH_CUBIC_TO_RELATIVE, c2x, c2y, x, y);
return this;
}
/**
* Smooth Cubic Bezier line to the given relative coordinates.
*
* @param c2xy second control point
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath relativeSmoothCubicTo(double[] c2xy, double[] xy) {
append(PATH_SMOOTH_CUBIC_TO_RELATIVE, c2xy[0], c2xy[1], xy[0], xy[1]);
return this;
}
/**
* Smooth Cubic Bezier line to the given relative coordinates.
*
* @param c2xy second control point
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath relativeSmoothCubicTo(Vector c2xy, Vector xy) {
append(PATH_SMOOTH_CUBIC_TO_RELATIVE, c2xy.doubleValue(0), c2xy.doubleValue(1), xy.doubleValue(0), xy.doubleValue(1));
return this;
}
/**
* Quadratic Bezier line to the given coordinates.
*
* @param c1x first control point x
* @param c1y first control point y
* @param x new coordinates
* @param y new coordinates
* @return path object, for compact syntax.
*/
public SVGPath quadTo(double c1x, double c1y, double x, double y) {
append(SVGConstants.PATH_QUAD_TO, c1x, c1y, x, y);
return this;
}
/**
* Quadratic Bezier line to the given coordinates.
*
* @param c1xy first control point
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath quadTo(double[] c1xy, double[] xy) {
append(SVGConstants.PATH_QUAD_TO, c1xy[0], c1xy[1], xy[0], xy[1]);
return this;
}
/**
* Quadratic Bezier line to the given coordinates.
*
* @param c1xy first control point
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath quadTo(Vector c1xy, Vector xy) {
append(SVGConstants.PATH_QUAD_TO, c1xy.doubleValue(0), c1xy.doubleValue(1), xy.doubleValue(0), xy.doubleValue(1));
return this;
}
/**
* Quadratic Bezier line to the given relative coordinates.
*
* @param c1x first control point x
* @param c1y first control point y
* @param x new coordinates
* @param y new coordinates
* @return path object, for compact syntax.
*/
public SVGPath relativeQuadTo(double c1x, double c1y, double x, double y) {
append(PATH_QUAD_TO_RELATIVE, c1x, c1y, x, y);
return this;
}
/**
* Quadratic Bezier line to the given relative coordinates.
*
* @param c1xy first control point
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath relativeQuadTo(double[] c1xy, double[] xy) {
append(PATH_QUAD_TO_RELATIVE, c1xy[0], c1xy[1], xy[0], xy[1]);
return this;
}
/**
* Quadratic Bezier line to the given relative coordinates.
*
* @param c1xy first control point
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath relativeQuadTo(Vector c1xy, Vector xy) {
append(PATH_QUAD_TO_RELATIVE, c1xy.doubleValue(0), c1xy.doubleValue(1), xy.doubleValue(0), xy.doubleValue(1));
return this;
}
/**
* Smooth quadratic Bezier line to the given coordinates.
*
* @param x new coordinates
* @param y new coordinates
* @return path object, for compact syntax.
*/
public SVGPath smoothQuadTo(double x, double y) {
append(SVGConstants.PATH_SMOOTH_QUAD_TO, x, y);
return this;
}
/**
* Smooth quadratic Bezier line to the given coordinates.
*
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath smoothQuadTo(double[] xy) {
append(SVGConstants.PATH_SMOOTH_QUAD_TO, xy[0], xy[1]);
return this;
}
/**
* Smooth quadratic Bezier line to the given coordinates.
*
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath smoothQuadTo(Vector xy) {
append(SVGConstants.PATH_SMOOTH_QUAD_TO, xy.doubleValue(0), xy.doubleValue(1));
return this;
}
/**
* Smooth quadratic Bezier line to the given relative coordinates.
*
* @param x new coordinates
* @param y new coordinates
* @return path object, for compact syntax.
*/
public SVGPath relativeSmoothQuadTo(double x, double y) {
append(PATH_SMOOTH_QUAD_TO_RELATIVE, x, y);
return this;
}
/**
* Smooth quadratic Bezier line to the given relative coordinates.
*
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath relativeSmoothQuadTo(double[] xy) {
append(PATH_SMOOTH_QUAD_TO_RELATIVE, xy[0], xy[1]);
return this;
}
/**
* Smooth quadratic Bezier line to the given relative coordinates.
*
* @param xy new coordinates
* @return path object, for compact syntax.
*/
public SVGPath relativeSmoothQuadTo(Vector xy) {
append(PATH_SMOOTH_QUAD_TO_RELATIVE, xy.doubleValue(0), xy.doubleValue(1));
return this;
}
/**
* Elliptical arc curve to the given coordinates.
*
* @param rx x radius
* @param ry y radius
* @param ar x-axis-rotation
* @param la large arc flag, if angle >= 180 deg
* @param sp sweep flag, if arc will be drawn in positive-angle direction
* @param x new coordinates
* @param y new coordinates
*/
public SVGPath ellipticalArc(double rx, double ry, double ar, double la, double sp, double x, double y) {
append(SVGConstants.PATH_ARC, rx, ry, ar, la, sp, x, y);
return this;
}
/**
* Elliptical arc curve to the given coordinates.
*
* @param rx x radius
* @param ry y radius
* @param ar x-axis-rotation
* @param la large arc flag, if angle >= 180 deg
* @param sp sweep flag, if arc will be drawn in positive-angle direction
* @param xy new coordinates
*/
public SVGPath ellipticalArc(double rx, double ry, double ar, double la, double sp, double[] xy) {
append(SVGConstants.PATH_ARC, rx, ry, ar, la, sp, xy[0], xy[1]);
return this;
}
/**
* Elliptical arc curve to the given coordinates.
*
* @param rxy radius
* @param ar x-axis-rotation
* @param la large arc flag, if angle >= 180 deg
* @param sp sweep flag, if arc will be drawn in positive-angle direction
* @param xy new coordinates
*/
public SVGPath ellipticalArc(Vector rxy, double ar, double la, double sp, Vector xy) {
append(SVGConstants.PATH_ARC, rxy.doubleValue(0), rxy.doubleValue(1), ar, la, sp, xy.doubleValue(0), xy.doubleValue(1));
return this;
}
/**
* Elliptical arc curve to the given relative coordinates.
*
* @param rx x radius
* @param ry y radius
* @param ar x-axis-rotation
* @param la large arc flag, if angle >= 180 deg
* @param sp sweep flag, if arc will be drawn in positive-angle direction
* @param x new coordinates
* @param y new coordinates
*/
public SVGPath relativeEllipticalArc(double rx, double ry, double ar, double la, double sp, double x, double y) {
append(PATH_ARC_RELATIVE, rx, ry, ar, la, sp, x, y);
return this;
}
/**
* Elliptical arc curve to the given relative coordinates.
*
* @param rx x radius
* @param ry y radius
* @param ar x-axis-rotation
* @param la large arc flag, if angle >= 180 deg
* @param sp sweep flag, if arc will be drawn in positive-angle direction
* @param xy new coordinates
*/
public SVGPath relativeEllipticalArc(double rx, double ry, double ar, double la, double sp, double[] xy) {
append(PATH_ARC_RELATIVE, rx, ry, ar, la, sp, xy[0], xy[1]);
return this;
}
/**
* Elliptical arc curve to the given relative coordinates.
*
* @param rxy radius
* @param ar x-axis-rotation
* @param la large arc flag, if angle >= 180 deg
* @param sp sweep flag, if arc will be drawn in positive-angle direction
* @param xy new coordinates
*/
public SVGPath relativeEllipticalArc(Vector rxy, double ar, double la, double sp, Vector xy) {
append(PATH_ARC_RELATIVE, rxy.doubleValue(0), rxy.doubleValue(1), ar, la, sp, xy.doubleValue(0), xy.doubleValue(1));
return this;
}
/**
* Append an action to the current path.
*
* @param action Current action
* @param ds coordinates.
*/
private void append(String action, double... ds) {
if(lastaction != action) {
buf.append(action);
lastaction = action;
}
for(double d : ds) {
buf.append(SVGUtil.FMT.format(d));
buf.append(' ');
}
}
/**
* Close the path.
*
* @return path object, for compact syntax.
*/
public SVGPath close() {
if(lastaction != SVGConstants.PATH_CLOSE) {
buf.append(SVGConstants.PATH_CLOSE);
lastaction = SVGConstants.PATH_CLOSE;
}
return this;
}
/**
* Turn the path buffer into an SVG element.
*
* @param document Document context (= element factory)
* @return SVG Element
*/
public Element makeElement(Document document) {
Element elem = SVGUtil.svgElement(document, SVGConstants.SVG_PATH_TAG);
elem.setAttribute(SVGConstants.SVG_D_ATTRIBUTE, buf.toString());
return elem;
}
/**
* Turn the path buffer into an SVG element.
*
* @param plot Plot context (= element factory)
* @return SVG Element
*/
public Element makeElement(SVGPlot plot) {
Element elem = plot.svgElement(SVGConstants.SVG_PATH_TAG);
elem.setAttribute(SVGConstants.SVG_D_ATTRIBUTE, buf.toString());
return elem;
}
/**
* Return the SVG serialization of the path.
*/
@Override
public String toString() {
return buf.toString();
}
}
elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/svg/SVGPlot.java 0000775 0000000 0000000 00000050445 12657057427 0033047 0 ustar 00root root 0000000 0000000 package de.lmu.ifi.dbs.elki.visualization.svg;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.batik.transcoder.Transcoder;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.XMLAbstractTranscoder;
import org.apache.batik.transcoder.image.JPEGTranscoder;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.events.Event;
import org.w3c.dom.svg.SVGDocument;
import org.w3c.dom.svg.SVGPoint;
import de.lmu.ifi.dbs.elki.logging.LoggingUtil;
import de.lmu.ifi.dbs.elki.utilities.FileUtil;
import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException;
import de.lmu.ifi.dbs.elki.visualization.batikutil.CloneInlineImages;
import de.lmu.ifi.dbs.elki.visualization.batikutil.ThumbnailTranscoder;
import de.lmu.ifi.dbs.elki.visualization.css.CSSClass;
import de.lmu.ifi.dbs.elki.visualization.css.CSSClassManager;
import de.lmu.ifi.dbs.elki.visualization.css.CSSClassManager.CSSNamingConflict;
/**
* Base class for SVG plots. Provides some basic functionality such as element
* creation, axis plotting, markers and number formatting for SVG.
*
* @author Erich Schubert
* @since 0.2
*
* @apiviz.landmark
* @apiviz.composedOf CSSClassManager
* @apiviz.composedOf UpdateRunner
* @apiviz.composedOf SVGDocument
* @apiviz.has Element oneway - - contains
* @apiviz.has UpdateSynchronizer oneway - - synchronizesWith
*/
public class SVGPlot {
/**
* Default JPEG quality setting
*/
public static final double DEFAULT_QUALITY = 0.85;
/**
* Attribute to block export of element.
*/
public static final String NO_EXPORT_ATTRIBUTE = "noexport";
/**
* Batik DOM implementation.
*/
private static final DOMImplementation BATIK_DOM;
/**
* DOM implementations to try.
*/
private static final String[] BATIK_DOMS = { //
"org.apache.batik.anim.dom.SVGDOMImplementation", // Batik 1.8
"org.apache.batik.dom.svg.SVGDOMImplementation", // Batik 1.7
"com.sun.org.apache.xerces.internal.dom.DOMImplementationImpl", // Untested
};
// Locate a usable DOM implementation.
static {
DOMImplementation dom = null;
for(String s : BATIK_DOMS) {
try {
Class> c = Class.forName(s);
Method m = c.getDeclaredMethod("getDOMImplementation");
DOMImplementation ret = DOMImplementation.class.cast(m.invoke(null));
if(ret != null) {
dom = ret;
break;
}
}
catch(Exception e) {
continue;
}
}
BATIK_DOM = dom;
}
/**
* SVG document we plot to.
*/
private SVGDocument document;
/**
* Root element of the document.
*/
private Element root;
/**
* Definitions element of the document.
*/
private Element defs;
/**
* Primary style information
*/
private Element style;
/**
* CSS class manager
*/
private CSSClassManager cssman;
/**
* Manage objects with an id.
*/
private HashMap> objWithId = new HashMap<>();
/**
* Registers changes of this SVGPlot.
*/
private UpdateRunner runner = new UpdateRunner(this);
/**
* Flag whether Batik interactions should be disabled.
*/
private boolean disableInteractions = false;
/**
* Create a new plotting document.
*/
public SVGPlot() {
super();
// Get a DOMImplementation.
DOMImplementation domImpl = getDomImpl();
DocumentType dt = domImpl.createDocumentType(SVGConstants.SVG_SVG_TAG, SVGConstants.SVG_PUBLIC_ID, SVGConstants.SVG_SYSTEM_ID);
// Workaround: sometimes DocumentType doesn't work right, which
// causes problems with
// serialization...
if(dt.getName() == null) {
dt = null;
}
document = (SVGDocument) domImpl.createDocument(SVGConstants.SVG_NAMESPACE_URI, SVGConstants.SVG_SVG_TAG, dt);
root = document.getDocumentElement();
// setup common SVG namespaces
root.setAttribute(SVGConstants.XMLNS_PREFIX, SVGConstants.SVG_NAMESPACE_URI);
root.setAttributeNS(SVGConstants.XMLNS_NAMESPACE_URI, SVGConstants.XMLNS_PREFIX + ":" + SVGConstants.XLINK_PREFIX, SVGConstants.XLINK_NAMESPACE_URI);
// create element for SVG definitions
defs = svgElement(SVGConstants.SVG_DEFS_TAG);
root.appendChild(defs);
// create element for Stylesheet information.
style = SVGUtil.makeStyleElement(document);
root.appendChild(style);
// create a CSS class manager.
cssman = new CSSClassManager();
}
/**
* Get a suitable SVG DOM implementation from Batik 1.7 or 1.8.
*
* @return DOM implementation
*/
public static DOMImplementation getDomImpl() {
if(BATIK_DOM == null) {
throw new AbortException("No usable Apache Batik SVG DOM could be located.");
}
return BATIK_DOM;
}
/**
* Clean up the plot.
*/
public void dispose() {
runner.clear();
}
/**
* Create a SVG element in the SVG namespace. Non-static version.
*
* @param name node name
* @return new SVG element.
*/
public Element svgElement(String name) {
return SVGUtil.svgElement(document, name);
}
/**
* Create a SVG rectangle
*
* @param x X coordinate
* @param y Y coordinate
* @param w Width
* @param h Height
* @return new element
*/
public Element svgRect(double x, double y, double w, double h) {
return SVGUtil.svgRect(document, x, y, w, h);
}
/**
* Create a SVG circle
*
* @param cx center X
* @param cy center Y
* @param r radius
* @return new element
*/
public Element svgCircle(double cx, double cy, double r) {
return SVGUtil.svgCircle(document, cx, cy, r);
}
/**
* Create a SVG line element
*
* @param x1 first point x
* @param y1 first point y
* @param x2 second point x
* @param y2 second point y
* @return new element
*/
public Element svgLine(double x1, double y1, double x2, double y2) {
return SVGUtil.svgLine(document, x1, y1, x2, y2);
}
/**
* Create a SVG text element.
*
* @param x first point x
* @param y first point y
* @param text Content of text element.
* @return New text element.
*/
public Element svgText(double x, double y, String text) {
return SVGUtil.svgText(document, x, y, text);
}
/**
* Convert screen coordinates to element coordinates.
*
* @param tag Element to convert the coordinates for
* @param evt Event object
* @return Coordinates
*/
public SVGPoint elementCoordinatesFromEvent(Element tag, Event evt) {
return SVGUtil.elementCoordinatesFromEvent(document, tag, evt);
}
/**
* Retrieve the SVG document.
*
* @return resulting document.
*/
public SVGDocument getDocument() {
return document;
}
/**
* Getter for root element.
*
* @return DOM element
*/
public Element getRoot() {
return root;
}
/**
* Getter for definitions section
*
* @return DOM element
*/
public Element getDefs() {
return defs;
}
/**
* Getter for style element.
*
* @return stylesheet DOM element
* @deprecated Contents will be overwritten by CSS class manager!
*/
@Deprecated
public Element getStyle() {
return style;
}
/**
* Get the plots CSS class manager.
*
* Note that you need to invoke {@link #updateStyleElement()} to make changes
* take effect.
*
* @return CSS class manager.
*/
public CSSClassManager getCSSClassManager() {
return cssman;
}
/**
* Convenience method to add a CSS class or log an error.
*
* @param cls CSS class to add.
*/
public void addCSSClassOrLogError(CSSClass cls) {
try {
cssman.addClass(cls);
}
catch(CSSNamingConflict e) {
de.lmu.ifi.dbs.elki.logging.LoggingUtil.exception(e);
}
}
/**
* Update style element - invoke this appropriately after any change to the
* CSS styles.
*/
public void updateStyleElement() {
// TODO: this should be sufficient - why does Batik occasionally not pick up
// the changes unless we actually replace the style element itself?
// cssman.updateStyleElement(document, style);
Element newstyle = cssman.makeStyleElement(document);
style.getParentNode().replaceChild(newstyle, style);
style = newstyle;
}
/**
* Save document into a SVG file.
*
* References PNG images from the temporary files will be inlined
* automatically.
*
* @param file Output filename
* @throws IOException On write errors
* @throws TransformerFactoryConfigurationError Transformation error
* @throws TransformerException Transformation error
*/
public void saveAsSVG(File file) throws IOException, TransformerFactoryConfigurationError, TransformerException {
OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
// TODO embed linked images.
javax.xml.transform.Result result = new StreamResult(out);
SVGDocument doc = cloneDocument();
// Use a transformer for pretty printing
Transformer xformer = TransformerFactory.newInstance().newTransformer();
xformer.setOutputProperty(OutputKeys.INDENT, "yes");
xformer.transform(new DOMSource(doc), result);
out.flush();
out.close();
}
/**
* Transcode a document into a file using the given transcoder.
*
* @param file Output file
* @param transcoder Transcoder to use
* @throws IOException On write errors
* @throws TranscoderException On input/parsing errors
*/
protected void transcode(File file, Transcoder transcoder) throws IOException, TranscoderException {
// Disable validation, performance is more important here (thumbnails!)
transcoder.addTranscodingHint(XMLAbstractTranscoder.KEY_XML_PARSER_VALIDATING, Boolean.FALSE);
SVGDocument doc = cloneDocument();
TranscoderInput input = new TranscoderInput(doc);
OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
TranscoderOutput output = new TranscoderOutput(out);
transcoder.transcode(input, output);
out.flush();
out.close();
}
/**
* Clone the SVGPlot document for transcoding.
*
* This will usually be necessary for exporting the SVG document if it is
* currently being displayed: otherwise, we break the Batik rendering trees.
* (Discovered by Simon).
*
* @return cloned document
*/
protected SVGDocument cloneDocument() {
return (SVGDocument) new CloneNoExport().cloneDocument(getDomImpl(), document);
}
/**
* Transcode file to PDF.
*
* @param file Output filename
* @throws IOException On write errors
* @throws TranscoderException On input/parsing errors.
* @throws ClassNotFoundException PDF transcoder not installed
*/
public void saveAsPDF(File file) throws IOException, TranscoderException, ClassNotFoundException {
try {
Object t = Class.forName("org.apache.fop.svg.PDFTranscoder").newInstance();
transcode(file, (Transcoder) t);
}
catch(InstantiationException e) {
throw new ClassNotFoundException("Could not instantiate PDF transcoder - is Apache FOP installed?", e);
}
catch(IllegalAccessException e) {
throw new ClassNotFoundException("Could not instantiate PDF transcoder - is Apache FOP installed?", e);
}
}
/**
* Transcode file to PS.
*
* @param file Output filename
* @throws IOException On write errors
* @throws TranscoderException On input/parsing errors.
* @throws ClassNotFoundException PS transcoder not installed
*/
public void saveAsPS(File file) throws IOException, TranscoderException, ClassNotFoundException {
try {
Object t = Class.forName("org.apache.fop.render.ps.PSTranscoder").newInstance();
transcode(file, (Transcoder) t);
}
catch(InstantiationException e) {
throw new ClassNotFoundException("Could not instantiate PS transcoder - is Apache FOP installed?", e);
}
catch(IllegalAccessException e) {
throw new ClassNotFoundException("Could not instantiate PS transcoder - is Apache FOP installed?", e);
}
}
/**
* Transcode file to EPS.
*
* @param file Output filename
* @throws IOException On write errors
* @throws TranscoderException On input/parsing errors.
* @throws ClassNotFoundException EPS transcoder not installed
*/
public void saveAsEPS(File file) throws IOException, TranscoderException, ClassNotFoundException {
try {
Object t = Class.forName("org.apache.fop.render.ps.EPSTranscoder").newInstance();
transcode(file, (Transcoder) t);
}
catch(InstantiationException e) {
throw new ClassNotFoundException("Could not instantiate EPS transcoder - is Apache FOP installed?", e);
}
catch(IllegalAccessException e) {
throw new ClassNotFoundException("Could not instantiate EPS transcoder - is Apache FOP installed?", e);
}
}
/**
* Transcode file to PNG.
*
* @param file Output filename
* @param width Width
* @param height Height
* @throws IOException On write errors
* @throws TranscoderException On input/parsing errors.
*/
public void saveAsPNG(File file, int width, int height) throws IOException, TranscoderException {
PNGTranscoder t = new PNGTranscoder();
t.addTranscodingHint(PNGTranscoder.KEY_WIDTH, new Float(width));
t.addTranscodingHint(PNGTranscoder.KEY_HEIGHT, new Float(height));
transcode(file, t);
}
/**
* Transcode file to JPEG.
*
* @param file Output filename
* @param width Width
* @param height Height
* @param quality JPEG quality setting, between 0.0 and 1.0
* @throws IOException On write errors
* @throws TranscoderException On input/parsing errors.
*/
public void saveAsJPEG(File file, int width, int height, double quality) throws IOException, TranscoderException {
JPEGTranscoder t = new JPEGTranscoder();
t.addTranscodingHint(JPEGTranscoder.KEY_WIDTH, new Float(width));
t.addTranscodingHint(JPEGTranscoder.KEY_HEIGHT, new Float(height));
t.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, new Float(quality));
transcode(file, t);
}
/**
* Transcode file to JPEG.
*
* @param file Output filename
* @param width Width
* @param height Height
* @throws IOException On write errors
* @throws TranscoderException On input/parsing errors.
*/
public void saveAsJPEG(File file, int width, int height) throws IOException, TranscoderException {
saveAsJPEG(file, width, height, DEFAULT_QUALITY);
}
/**
* Save a file trying to auto-guess the file type.
*
* @param file File name
* @param width Width (for pixel formats)
* @param height Height (for pixel formats)
* @param quality Quality (for lossy compression)
* @throws IOException on file write errors or unrecognized file extensions
* @throws TranscoderException on transcoding errors
* @throws TransformerFactoryConfigurationError on transcoding errors
* @throws TransformerException on transcoding errors
* @throws ClassNotFoundException when the transcoder was not installed
*/
public void saveAsANY(File file, int width, int height, double quality) throws IOException, TranscoderException, TransformerFactoryConfigurationError, TransformerException, ClassNotFoundException {
String extension = FileUtil.getFilenameExtension(file);
if(extension.equals("svg")) {
saveAsSVG(file);
}
else if(extension.equals("pdf")) {
saveAsPDF(file);
}
else if(extension.equals("ps")) {
saveAsPS(file);
}
else if(extension.equals("eps")) {
saveAsEPS(file);
}
else if(extension.equals("png")) {
saveAsPNG(file, width, height);
}
else if(extension.equals("jpg") || extension.equals("jpeg")) {
saveAsJPEG(file, width, height, quality);
}
else {
throw new IOException("Unknown file extension: " + extension);
}
}
/**
* Convert the SVG to a thumbnail image.
*
* @param width Width of thumbnail
* @param height Height of thumbnail
* @return Buffered image
*/
public BufferedImage makeAWTImage(int width, int height) throws TranscoderException {
ThumbnailTranscoder t = new ThumbnailTranscoder();
t.addTranscodingHint(PNGTranscoder.KEY_WIDTH, new Float(width));
t.addTranscodingHint(PNGTranscoder.KEY_HEIGHT, new Float(height));
// Don't clone. Assume this is used safely.
TranscoderInput input = new TranscoderInput(document);
t.transcode(input, null);
return t.getLastImage();
}
/**
* Dump the SVG plot to a debug file.
*/
public void dumpDebugFile() {
try {
File f = File.createTempFile("elki-debug", ".svg");
f.deleteOnExit();
this.saveAsSVG(f);
LoggingUtil.warning("Saved debug file to: " + f.getAbsolutePath());
}
catch(Throwable err) {
// Ignore.
}
}
/**
* Add an object id.
*
* @param id ID
* @param obj Element
*/
public void putIdElement(String id, Element obj) {
objWithId.put(id, new WeakReference<>(obj));
}
/**
* Get an element by its id.
*
* @param id ID
* @return Element
*/
public Element getIdElement(String id) {
WeakReference ref = objWithId.get(id);
return (ref != null) ? ref.get() : null;
}
/**
* Get all used DOM Ids in this plot.
*
* @return Collection of DOM element IDs.
*/
protected Collection getAllIds() {
return objWithId.keySet();
}
/**
* Schedule an update.
*
* @param runnable Runnable to schedule
*/
public void scheduleUpdate(Runnable runnable) {
runner.invokeLater(runnable);
}
/**
* Assign an update synchronizer.
*
* @param sync Update synchronizer
*/
public void synchronizeWith(UpdateSynchronizer sync) {
runner.synchronizeWith(sync);
}
/**
* Detach from synchronization.
*
* @param sync Update synchronizer to detach from.
*/
public void unsynchronizeWith(UpdateSynchronizer sync) {
runner.unsynchronizeWith(sync);
}
/**
* Get Batik disable default interactions flag.
*
* @return true when Batik default interactions are disabled
*/
public boolean getDisableInteractions() {
return disableInteractions;
}
/**
* Disable Batik predefined interactions.
*
* @param disable Flag
*/
public void setDisableInteractions(boolean disable) {
disableInteractions = disable;
}
/**
* Class to skip nodes during cloning that have the "noexport" attribute set.
*
* @author Erich Schubert
*
* @apiviz.exclude
*/
protected class CloneNoExport extends CloneInlineImages {
@Override
public Node cloneNode(Document doc, Node eold) {
// Skip elements with noexport attribute set
if(eold instanceof Element) {
Element eeold = (Element) eold;
String vis = eeold.getAttribute(NO_EXPORT_ATTRIBUTE);
if(vis != null && vis.length() > 0) {
return null;
}
}
return super.cloneNode(doc, eold);
}
}
} SVGScoreBar.java 0000664 0000000 0000000 00000010632 12657057427 0033541 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/svg package de.lmu.ifi.dbs.elki.visualization.svg;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.text.NumberFormat;
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
/**
* Draw a score bar. Essentially like a progress bar, left-to-right, displaying
* a relative score.
*
* @author Sascha Goldhofer
* @since 0.5.0
*/
// TODO: refactor to get a progress bar?
public class SVGScoreBar {
/**
* Value, minimum and maximum values
*/
protected double val, min = 0., max = 1.;
/**
* Reversed flag.
*/
protected boolean reversed = false;
/**
* Label (on the right)
*/
protected String label = null;
/**
* Number format, set to print the actual score
*/
private NumberFormat format = null;
/**
* Constructor.
*/
public SVGScoreBar() {
// Nothing to do here.
}
/**
* Set the fill of the score bar.
*
* @param val Value
* @param min Minimum value
* @param max Maximum value
*/
public void setFill(double val, double min, double max) {
this.val = val;
this.min = min;
this.max = max;
}
/**
* Set the reversed flag.
*
* @param reversed Reversed flag.
*/
public void setReversed(boolean reversed) {
this.reversed = reversed;
}
/**
* Set label (right of the bar)
*
* @param text Label text
*/
public void addLabel(String text) {
this.label = text;
}
/**
* To show score values, set a number format
*
* @param format Number format
*/
public void showValues(NumberFormat format) {
this.format = format;
}
/**
* Build the actual element
*
* @param svgp Plot to draw to
* @param x X coordinate
* @param y Y coordinate
* @param width Width
* @param height Height
* @return new element
*/
public Element build(SVGPlot svgp, double x, double y, double width, double height) {
Element barchart = svgp.svgElement(SVGConstants.SVG_G_TAG);
// TODO: use style library for colors!
Element bar = svgp.svgRect(x, y, width, height);
bar.setAttribute(SVGConstants.SVG_FILL_ATTRIBUTE, "#a0a0a0");
bar.setAttribute(SVGConstants.SVG_STROKE_ATTRIBUTE, "#a0a0a0");
bar.setAttribute(SVGConstants.SVG_STROKE_WIDTH_ATTRIBUTE, String.valueOf(height * 0.01));
barchart.appendChild(bar);
if(val >= min && val <= max && min < max) {
final double frame = 0.02 * height;
double fpos = (val - min) / (max - min) * (width - 2 * frame);
Element chart;
if(reversed) {
chart = svgp.svgRect(x + frame + fpos, y + frame, width - fpos - 2 * frame, height - 2 * frame);
}
else {
chart = svgp.svgRect(x + frame, y + frame, fpos, height - 2 * frame);
}
chart.setAttribute(SVGConstants.SVG_FILL_ATTRIBUTE, "#d4e4f1");
chart.setAttribute(SVGConstants.SVG_STROKE_ATTRIBUTE, "#a0a0a0");
chart.setAttribute(SVGConstants.SVG_STROKE_WIDTH_ATTRIBUTE, String.valueOf(height * 0.01));
barchart.appendChild(chart);
}
// Draw the values:
if(format != null) {
String num = Double.isNaN(val) ? "NaN" : format.format(val);
Element lbl = svgp.svgText(x + 0.05 * width, y + 0.75 * height, num);
lbl.setAttribute(SVGConstants.SVG_STYLE_ATTRIBUTE, "font-size: " + 0.75 * height + "; font-weight: bold");
barchart.appendChild(lbl);
}
// Draw the label
if(label != null) {
Element lbl = svgp.svgText(x + 1.05 * width, y + 0.75 * height, label);
lbl.setAttribute(SVGConstants.SVG_STYLE_ATTRIBUTE, "font-size: " + 0.75 * height + "; font-weight: normal");
barchart.appendChild(lbl);
}
return barchart;
}
} SVGSimpleLinearAxis.java 0000775 0000000 0000000 00000022373 12657057427 0035262 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/svg package de.lmu.ifi.dbs.elki.visualization.svg;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
import de.lmu.ifi.dbs.elki.math.scales.LinearScale;
import de.lmu.ifi.dbs.elki.visualization.css.CSSClass;
import de.lmu.ifi.dbs.elki.visualization.css.CSSClassManager;
import de.lmu.ifi.dbs.elki.visualization.css.CSSClassManager.CSSNamingConflict;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
/**
* Class to draw a simple axis with tick marks on the plot.
*
* @author Erich Schubert
* @since 0.2
*
* @apiviz.uses CSSClass
* @apiviz.uses CSSClassManager
* @apiviz.uses LinearScale
* @apiviz.uses StyleLibrary
* @apiviz.uses Element oneway - - «create»
*/
public class SVGSimpleLinearAxis {
/**
* Flag for axis label position. First char: right-hand or left-hand side of
* line. Second char: text alignment
*
* @apiviz.exclude
*/
private enum Alignment {
LL, RL, LC, RC, LR, RR
}
/**
* Labeling style: left-handed, right-handed, no ticks, labels at ends
*
* @apiviz.exclude
*/
public enum LabelStyle {
LEFTHAND, RIGHTHAND, NOLABELS, NOTHING, ENDLABEL
}
/**
* CSS class name for the axes
*/
private static final String CSS_AXIS = "axis";
/**
* CSS class name for the axes
*/
private static final String CSS_AXIS_TICK = "axis-tick";
/**
* CSS class name for the axes
*/
private static final String CSS_AXIS_LABEL = "axis-label";
/**
* Register CSS classes with a {@link CSSClassManager}
*
* @param owner Owner of the CSS classes
* @param manager Manager to register the classes with
* @throws CSSNamingConflict when a name clash occurs
*/
private static void setupCSSClasses(Object owner, CSSClassManager manager, StyleLibrary style) throws CSSNamingConflict {
if(!manager.contains(CSS_AXIS)) {
CSSClass axis = new CSSClass(owner, CSS_AXIS);
axis.setStatement(SVGConstants.CSS_STROKE_PROPERTY, style.getColor(StyleLibrary.AXIS));
axis.setStatement(SVGConstants.CSS_STROKE_WIDTH_PROPERTY, style.getLineWidth(StyleLibrary.AXIS));
manager.addClass(axis);
}
if(!manager.contains(CSS_AXIS_TICK)) {
CSSClass tick = new CSSClass(owner, CSS_AXIS_TICK);
tick.setStatement(SVGConstants.CSS_STROKE_PROPERTY, style.getColor(StyleLibrary.AXIS_TICK));
tick.setStatement(SVGConstants.CSS_STROKE_WIDTH_PROPERTY, style.getLineWidth(StyleLibrary.AXIS_TICK));
manager.addClass(tick);
}
if(!manager.contains(CSS_AXIS_LABEL)) {
CSSClass label = new CSSClass(owner, CSS_AXIS_LABEL);
label.setStatement(SVGConstants.CSS_FILL_PROPERTY, style.getTextColor(StyleLibrary.AXIS_LABEL));
label.setStatement(SVGConstants.CSS_FONT_FAMILY_PROPERTY, style.getFontFamily(StyleLibrary.AXIS_LABEL));
label.setStatement(SVGConstants.CSS_FONT_SIZE_PROPERTY, style.getTextSize(StyleLibrary.AXIS_LABEL));
manager.addClass(label);
}
}
/**
* Plot an axis with appropriate scales
*
* @param plot Plot object
* @param parent Containing element
* @param scale axis scale information
* @param x1 starting coordinate
* @param y1 starting coordinate
* @param x2 ending coordinate
* @param y2 ending coordinate
* @param labelstyle Style for placing the labels
* @param style Style library
* @throws CSSNamingConflict when a conflict occurs in CSS
*/
public static void drawAxis(SVGPlot plot, Element parent, LinearScale scale, double x1, double y1, double x2, double y2, LabelStyle labelstyle, StyleLibrary style) throws CSSNamingConflict {
assert (parent != null);
Element line = plot.svgLine(x1, y1, x2, y2);
SVGUtil.setCSSClass(line, CSS_AXIS);
parent.appendChild(line);
final double tx = x2 - x1;
final double ty = y2 - y1;
// ticks are orthogonal
final double tw = ty * 0.01;
final double th = -tx * 0.01;
// choose where to print labels.
final boolean labels, ticks;
switch(labelstyle){
case LEFTHAND:
case RIGHTHAND:
labels = true;
ticks = true;
break;
case NOLABELS:
labels = false;
ticks = true;
break;
case ENDLABEL: // end labels are handle specially
case NOTHING:
default:
labels = false;
ticks = false;
}
Alignment pos = Alignment.LL;
if(labels) {
double angle = Math.atan2(ty, tx);
// System.err.println(tx + " " + (-ty) + " " + angle);
if(angle > 2.6) { // pi .. 2.6 = 180 .. 150
pos = labelstyle == LabelStyle.RIGHTHAND ? Alignment.RC : Alignment.LC;
}
else if(angle > 0.5) { // 2.3 .. 0.7 = 130 .. 40
pos = labelstyle == LabelStyle.RIGHTHAND ? Alignment.RR : Alignment.LL;
}
else if(angle > -0.5) { // 0.5 .. -0.5 = 30 .. -30
pos = labelstyle == LabelStyle.RIGHTHAND ? Alignment.RC : Alignment.LC;
}
else if(angle > -2.6) { // -0.5 .. -2.6 = -30 .. -150
pos = labelstyle == LabelStyle.RIGHTHAND ? Alignment.RL : Alignment.LR;
}
else { // -2.6 .. -pi = -150 .. -180
pos = labelstyle == LabelStyle.RIGHTHAND ? Alignment.RC : Alignment.LC;
}
}
// vertical text offset; align approximately with middle instead of
// baseline.
double textvoff = style.getTextSize(StyleLibrary.AXIS_LABEL) * .35;
// draw ticks on x axis
if(ticks || labels) {
int sw = 1;
{ // Compute how many ticks to draw
int numticks = (int) ((scale.getMax() - scale.getMin()) / scale.getRes());
double tlen = Math.sqrt(tx * tx + ty * ty);
double minl = 10 * style.getLineWidth(StyleLibrary.AXIS_TICK);
// Try proper divisors first.
if(sw * tlen / numticks < minl) {
for(int i = 2; i <= (numticks >> 1); i++) {
if(numticks % i == 0) {
if(i * tlen / numticks >= minl) {
sw = i;
break;
}
}
}
}
// Otherwise, also allow non-divisors.
if(sw * tlen / numticks < minl) {
sw = (int)Math.floor(minl * numticks / tlen);
}
}
for(double tick = scale.getMin(); tick <= scale.getMax() + scale.getRes() / 10; tick += sw * scale.getRes()) {
double x = x1 + tx * scale.getScaled(tick);
double y = y1 + ty * scale.getScaled(tick);
if(ticks) {
// This is correct. Vectors: (vec - tvec) to (vec + tvec)
Element tickline = plot.svgLine(x - tw, y - th, x + tw, y + th);
SVGUtil.setAtt(tickline, SVGConstants.SVG_CLASS_ATTRIBUTE, CSS_AXIS_TICK);
parent.appendChild(tickline);
}
// draw labels
if(labels) {
double tex = x;
double tey = y;
switch(pos){
case LL:
case LC:
case LR:
tex = x + tw * 2.5;
tey = y + th * 2.5 + textvoff;
break;
case RL:
case RC:
case RR:
tex = x - tw * 2.5;
tey = y - th * 2.5 + textvoff;
}
Element text = plot.svgText(tex, tey, scale.formatValue(tick));
text.setAttribute(SVGConstants.SVG_CLASS_ATTRIBUTE, CSS_AXIS_LABEL);
switch(pos){
case LL:
case RL:
text.setAttribute(SVGConstants.SVG_TEXT_ANCHOR_ATTRIBUTE, SVGConstants.SVG_START_VALUE);
break;
case LC:
case RC:
text.setAttribute(SVGConstants.SVG_TEXT_ANCHOR_ATTRIBUTE, SVGConstants.SVG_MIDDLE_VALUE);
break;
case LR:
case RR:
text.setAttribute(SVGConstants.SVG_TEXT_ANCHOR_ATTRIBUTE, SVGConstants.SVG_END_VALUE);
break;
}
parent.appendChild(text);
}
}
}
if(labelstyle == LabelStyle.ENDLABEL) {
{
Element text = plot.svgText(x1 - tx * 0.02, y1 - ty * 0.02 + textvoff, scale.formatValue(scale.getMin()));
text.setAttribute(SVGConstants.SVG_CLASS_ATTRIBUTE, CSS_AXIS_LABEL);
text.setAttribute(SVGConstants.SVG_TEXT_ANCHOR_ATTRIBUTE, SVGConstants.SVG_MIDDLE_VALUE);
parent.appendChild(text);
}
{
Element text = plot.svgText(x2 + tx * 0.02, y2 + ty * 0.02 + textvoff, scale.formatValue(scale.getMax()));
text.setAttribute(SVGConstants.SVG_CLASS_ATTRIBUTE, CSS_AXIS_LABEL);
text.setAttribute(SVGConstants.SVG_TEXT_ANCHOR_ATTRIBUTE, SVGConstants.SVG_MIDDLE_VALUE);
parent.appendChild(text);
}
}
setupCSSClasses(plot, plot.getCSSClassManager(), style);
}
} elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/svg/SVGUtil.java 0000775 0000000 0000000 00000061326 12657057427 0033046 0 ustar 00root root 0000000 0000000 package de.lmu.ifi.dbs.elki.visualization.svg;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.awt.Color;
import java.text.NumberFormat;
import java.util.Locale;
import javax.swing.text.html.StyleSheet;
import org.apache.batik.dom.events.DOMMouseEvent;
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.events.Event;
import org.w3c.dom.svg.SVGDocument;
import org.w3c.dom.svg.SVGLocatable;
import org.w3c.dom.svg.SVGMatrix;
import org.w3c.dom.svg.SVGPoint;
import de.lmu.ifi.dbs.elki.logging.LoggingUtil;
import de.lmu.ifi.dbs.elki.math.MathUtil;
import gnu.trove.map.hash.TObjectIntHashMap;
/**
* Utility class for SVG processing.
*
* Much of the classes are to allow easier attribute setting (conversion to
* string) and Namespace handling
*
* @author Erich Schubert
* @since 0.2
*
* @apiviz.uses Element oneway - - «create»
*/
public final class SVGUtil {
/**
* Formatter to output numbers in a valid SVG number format.
*/
public static final NumberFormat FMT = NumberFormat.getInstance(Locale.ROOT);
static {
FMT.setMaximumFractionDigits(10);
FMT.setGroupingUsed(false);
}
/**
* Hourglass object.
*/
final public static String HOURGLASS_PATH = "M.35 .2 L.65 .2 L.65 .3 L.35 .7 L.35 .8 L.65 .8 L.65 .7 L.35 .3 Z";
/**
* Hourglass style.
*/
final public static String HOURGLASS_STYLE = "stroke: black; stroke-width: .01; fill: grey; opacity: .2";
/**
* Throbber path.
*/
final public static String THROBBER_PATH = "M.5,.25 a.25,.25 0 0 1 .1766,.42635 l-.0589 -.0589 a-.1766 -.1766 0 0 0 -.1178,-.2835 z";
/**
* Throbber style.
*/
final public static String THROBBER_STYLE = "fill: #3d7fe6; opacity: .2";
/**
* SVG color names conversion.
*/
final private static TObjectIntHashMap SVG_COLOR_NAMES;
/**
* Key not found value. Not a reasonable color, fully transparent!
*/
final private static int NO_VALUE = 0x00123456;
static {
// Build a reasonably sized hashmap. Use 0
SVG_COLOR_NAMES = new TObjectIntHashMap<>(90, .8f, NO_VALUE);
// List taken from SVG specification:
// http://www.w3.org/TR/SVG/types.html#ColorKeywords
SVG_COLOR_NAMES.put("aliceblue", 0xFFF0F8FF);
SVG_COLOR_NAMES.put("antiquewhite", 0xFFFAEBD7);
SVG_COLOR_NAMES.put("aqua", 0xFF00FFFF);
SVG_COLOR_NAMES.put("aquamarine", 0xFF7FFFD4);
SVG_COLOR_NAMES.put("azure", 0xFFF0FFFF);
SVG_COLOR_NAMES.put("beige", 0xFFF5F5DC);
SVG_COLOR_NAMES.put("bisque", 0xFFFFE4C4);
SVG_COLOR_NAMES.put("black", 0xFF000000);
SVG_COLOR_NAMES.put("blanchedalmond", 0xFFFFEBCD);
SVG_COLOR_NAMES.put("blue", 0xFF0000FF);
SVG_COLOR_NAMES.put("blueviolet", 0xFF8A2BE2);
SVG_COLOR_NAMES.put("brown", 0xFFA52A2A);
SVG_COLOR_NAMES.put("burlywood", 0xFFDEB887);
SVG_COLOR_NAMES.put("cadetblue", 0xFF5F9EA0);
SVG_COLOR_NAMES.put("chartreuse", 0xFF7FFF00);
SVG_COLOR_NAMES.put("chocolate", 0xFFD2691E);
SVG_COLOR_NAMES.put("coral", 0xFFFF7F50);
SVG_COLOR_NAMES.put("cornflowerblue", 0xFF6495ED);
SVG_COLOR_NAMES.put("cornsilk", 0xFFFFF8DC);
SVG_COLOR_NAMES.put("crimson", 0xFFDC143C);
SVG_COLOR_NAMES.put("cyan", 0xFF00FFFF);
SVG_COLOR_NAMES.put("darkblue", 0xFF00008B);
SVG_COLOR_NAMES.put("darkcyan", 0xFF008B8B);
SVG_COLOR_NAMES.put("darkgoldenrod", 0xFFB8860B);
SVG_COLOR_NAMES.put("darkgray", 0xFFA9A9A9);
SVG_COLOR_NAMES.put("darkgreen", 0xFF006400);
SVG_COLOR_NAMES.put("darkgrey", 0xFFA9A9A9);
SVG_COLOR_NAMES.put("darkkhaki", 0xFFBDB76B);
SVG_COLOR_NAMES.put("darkmagenta", 0xFF8B008B);
SVG_COLOR_NAMES.put("darkolivegreen", 0xFF556B2F);
SVG_COLOR_NAMES.put("darkorange", 0xFFFF8C00);
SVG_COLOR_NAMES.put("darkorchid", 0xFF9932CC);
SVG_COLOR_NAMES.put("darkred", 0xFF8B0000);
SVG_COLOR_NAMES.put("darksalmon", 0xFFE9967A);
SVG_COLOR_NAMES.put("darkseagreen", 0xFF8FBC8F);
SVG_COLOR_NAMES.put("darkslateblue", 0xFF483D8B);
SVG_COLOR_NAMES.put("darkslategray", 0xFF2F4F4F);
SVG_COLOR_NAMES.put("darkslategrey", 0xFF2F4F4F);
SVG_COLOR_NAMES.put("darkturquoise", 0xFF00CED1);
SVG_COLOR_NAMES.put("darkviolet", 0xFF9400D3);
SVG_COLOR_NAMES.put("deeppink", 0xFFFF1493);
SVG_COLOR_NAMES.put("deepskyblue", 0xFF00BFFF);
SVG_COLOR_NAMES.put("dimgray", 0xFF696969);
SVG_COLOR_NAMES.put("dimgrey", 0xFF696969);
SVG_COLOR_NAMES.put("dodgerblue", 0xFF1E90FF);
SVG_COLOR_NAMES.put("firebrick", 0xFFB22222);
SVG_COLOR_NAMES.put("floralwhite", 0xFFFFFAF0);
SVG_COLOR_NAMES.put("forestgreen", 0xFF228B22);
SVG_COLOR_NAMES.put("fuchsia", 0xFFFF00FF);
SVG_COLOR_NAMES.put("gainsboro", 0xFFDCDCDC);
SVG_COLOR_NAMES.put("ghostwhite", 0xFFF8F8FF);
SVG_COLOR_NAMES.put("gold", 0xFFFFD700);
SVG_COLOR_NAMES.put("goldenrod", 0xFFDAA520);
SVG_COLOR_NAMES.put("gray", 0xFF808080);
SVG_COLOR_NAMES.put("grey", 0xFF808080);
SVG_COLOR_NAMES.put("green", 0xFF008000);
SVG_COLOR_NAMES.put("greenyellow", 0xFFADFF2F);
SVG_COLOR_NAMES.put("honeydew", 0xFFF0FFF0);
SVG_COLOR_NAMES.put("hotpink", 0xFFFF69B4);
SVG_COLOR_NAMES.put("indianred", 0xFFCD5C5C);
SVG_COLOR_NAMES.put("indigo", 0xFF4B0082);
SVG_COLOR_NAMES.put("ivory", 0xFFFFFFF0);
SVG_COLOR_NAMES.put("khaki", 0xFFF0E68C);
SVG_COLOR_NAMES.put("lavender", 0xFFE6E6FA);
SVG_COLOR_NAMES.put("lavenderblush", 0xFFFFF0F5);
SVG_COLOR_NAMES.put("lawngreen", 0xFF7CFC00);
SVG_COLOR_NAMES.put("lemonchiffon", 0xFFFFFACD);
SVG_COLOR_NAMES.put("lightblue", 0xFFADD8E6);
SVG_COLOR_NAMES.put("lightcoral", 0xFFF08080);
SVG_COLOR_NAMES.put("lightcyan", 0xFFE0FFFF);
SVG_COLOR_NAMES.put("lightgoldenrodyellow", 0xFFFAFAD2);
SVG_COLOR_NAMES.put("lightgray", 0xFFD3D3D3);
SVG_COLOR_NAMES.put("lightgreen", 0xFF90EE90);
SVG_COLOR_NAMES.put("lightgrey", 0xFFD3D3D3);
SVG_COLOR_NAMES.put("lightpink", 0xFFFFB6C1);
SVG_COLOR_NAMES.put("lightsalmon", 0xFFFFA07A);
SVG_COLOR_NAMES.put("lightseagreen", 0xFF20B2AA);
SVG_COLOR_NAMES.put("lightskyblue", 0xFF87CEFA);
SVG_COLOR_NAMES.put("lightslategray", 0xFF778899);
SVG_COLOR_NAMES.put("lightslategrey", 0xFF778899);
SVG_COLOR_NAMES.put("lightsteelblue", 0xFFB0C4DE);
SVG_COLOR_NAMES.put("lightyellow", 0xFFFFFFE0);
SVG_COLOR_NAMES.put("lime", 0xFF00FF00);
SVG_COLOR_NAMES.put("limegreen", 0xFF32CD32);
SVG_COLOR_NAMES.put("linen", 0xFFFAF0E6);
SVG_COLOR_NAMES.put("magenta", 0xFFFF00FF);
SVG_COLOR_NAMES.put("maroon", 0xFF800000);
SVG_COLOR_NAMES.put("mediumaquamarine", 0xFF66CDAA);
SVG_COLOR_NAMES.put("mediumblue", 0xFF0000CD);
SVG_COLOR_NAMES.put("mediumorchid", 0xFFBA55D3);
SVG_COLOR_NAMES.put("mediumpurple", 0xFF9370DB);
SVG_COLOR_NAMES.put("mediumseagreen", 0xFF3CB371);
SVG_COLOR_NAMES.put("mediumslateblue", 0xFF7B68EE);
SVG_COLOR_NAMES.put("mediumspringgreen", 0xFF00FA9A);
SVG_COLOR_NAMES.put("mediumturquoise", 0xFF48D1CC);
SVG_COLOR_NAMES.put("mediumvioletred", 0xFFC71585);
SVG_COLOR_NAMES.put("midnightblue", 0xFF191970);
SVG_COLOR_NAMES.put("mintcream", 0xFFF5FFFA);
SVG_COLOR_NAMES.put("mistyrose", 0xFFFFE4E1);
SVG_COLOR_NAMES.put("moccasin", 0xFFFFE4B5);
SVG_COLOR_NAMES.put("navajowhite", 0xFFFFDEAD);
SVG_COLOR_NAMES.put("navy", 0xFF000080);
SVG_COLOR_NAMES.put("oldlace", 0xFFFDF5E6);
SVG_COLOR_NAMES.put("olive", 0xFF808000);
SVG_COLOR_NAMES.put("olivedrab", 0xFF6B8E23);
SVG_COLOR_NAMES.put("orange", 0xFFFFA500);
SVG_COLOR_NAMES.put("orangered", 0xFFFF4500);
SVG_COLOR_NAMES.put("orchid", 0xFFDA70D6);
SVG_COLOR_NAMES.put("palegoldenrod", 0xFFEEE8AA);
SVG_COLOR_NAMES.put("palegreen", 0xFF98FB98);
SVG_COLOR_NAMES.put("paleturquoise", 0xFFAFEEEE);
SVG_COLOR_NAMES.put("palevioletred", 0xFFDB7093);
SVG_COLOR_NAMES.put("papayawhip", 0xFFFFEFD5);
SVG_COLOR_NAMES.put("peachpuff", 0xFFFFDAB9);
SVG_COLOR_NAMES.put("peru", 0xFFCD853F);
SVG_COLOR_NAMES.put("pink", 0xFFFFC0CB);
SVG_COLOR_NAMES.put("plum", 0xFFDDA0DD);
SVG_COLOR_NAMES.put("powderblue", 0xFFB0E0E6);
SVG_COLOR_NAMES.put("purple", 0xFF800080);
SVG_COLOR_NAMES.put("red", 0xFFFF0000);
SVG_COLOR_NAMES.put("rosybrown", 0xFFBC8F8F);
SVG_COLOR_NAMES.put("royalblue", 0xFF4169E1);
SVG_COLOR_NAMES.put("saddlebrown", 0xFF8B4513);
SVG_COLOR_NAMES.put("salmon", 0xFFFA8072);
SVG_COLOR_NAMES.put("sandybrown", 0xFFF4A460);
SVG_COLOR_NAMES.put("seagreen", 0xFF2E8B57);
SVG_COLOR_NAMES.put("seashell", 0xFFFFF5EE);
SVG_COLOR_NAMES.put("sienna", 0xFFA0522D);
SVG_COLOR_NAMES.put("silver", 0xFFC0C0C0);
SVG_COLOR_NAMES.put("skyblue", 0xFF87CEEB);
SVG_COLOR_NAMES.put("slateblue", 0xFF6A5ACD);
SVG_COLOR_NAMES.put("slategray", 0xFF708090);
SVG_COLOR_NAMES.put("slategrey", 0xFF708090);
SVG_COLOR_NAMES.put("snow", 0xFFFFFAFA);
SVG_COLOR_NAMES.put("springgreen", 0xFF00FF7F);
SVG_COLOR_NAMES.put("steelblue", 0xFF4682B4);
SVG_COLOR_NAMES.put("tan", 0xFFD2B48C);
SVG_COLOR_NAMES.put("teal", 0xFF008080);
SVG_COLOR_NAMES.put("thistle", 0xFFD8BFD8);
SVG_COLOR_NAMES.put("tomato", 0xFFFF6347);
SVG_COLOR_NAMES.put("turquoise", 0xFF40E0D0);
SVG_COLOR_NAMES.put("violet", 0xFFEE82EE);
SVG_COLOR_NAMES.put("wheat", 0xFFF5DEB3);
SVG_COLOR_NAMES.put("white", 0xFFFFFFFF);
SVG_COLOR_NAMES.put("whitesmoke", 0xFFF5F5F5);
SVG_COLOR_NAMES.put("yellow", 0xFFFFFF00);
SVG_COLOR_NAMES.put("yellowgreen", 0xFF9ACD32);
// Nonstandard:
SVG_COLOR_NAMES.put("transparent", 0xFFFFFFFF);
}
/**
* CSS Stylesheet from Javax, to parse color values.
*/
private static final StyleSheet colorLookupStylesheet = new StyleSheet();
/**
* Format a double according to the SVG specs.
*
* @param x number to format
* @return String representation
*/
public static String fmt(double x) {
return FMT.format(x);
}
/**
* Create a SVG element in appropriate namespace
*
* @param document containing document
* @param name node name
* @return new SVG element.
*/
public static Element svgElement(Document document, String name) {
return document.createElementNS(SVGConstants.SVG_NAMESPACE_URI, name);
}
/**
* Set a SVG attribute
*
* @param el element
* @param name attribute name
* @param d double value
*/
public static void setAtt(Element el, String name, double d) {
el.setAttribute(name, fmt(d));
}
/**
* Set a SVG attribute
*
* @param el element
* @param name attribute name
* @param d integer value
*/
public static void setAtt(Element el, String name, int d) {
el.setAttribute(name, Integer.toString(d));
}
/**
* Set a SVG attribute
*
* @param el element
* @param name attribute name
* @param d string value
*/
public static void setAtt(Element el, String name, String d) {
el.setAttribute(name, d);
}
/**
* Set a SVG style attribute
*
* @param el element
* @param d style value
*/
public static void setStyle(Element el, String d) {
el.setAttribute(SVGConstants.SVG_STYLE_ATTRIBUTE, d);
}
/**
* Set the CSS class of an Element. See also {@link #addCSSClass} and
* {@link #removeCSSClass}.
*
* @param e Element
* @param cssclass class to set.
*/
public static void setCSSClass(Element e, String cssclass) {
setAtt(e, SVGConstants.SVG_CLASS_ATTRIBUTE, cssclass);
}
/**
* Add a CSS class to an Element.
*
* @param e Element
* @param cssclass class to add.
*/
public static void addCSSClass(Element e, String cssclass) {
String oldval = e.getAttribute(SVGConstants.SVG_CLASS_ATTRIBUTE);
if(oldval == null || oldval.length() == 0) {
setAtt(e, SVGConstants.SVG_CLASS_ATTRIBUTE, cssclass);
return;
}
String[] classes = oldval.split(" ");
for(String c : classes) {
if(c.equals(cssclass)) {
return;
}
}
setAtt(e, SVGConstants.SVG_CLASS_ATTRIBUTE, oldval + " " + cssclass);
}
/**
* Remove a CSS class from an Element.
*
* @param e Element
* @param cssclass class to remove.
*/
public static void removeCSSClass(Element e, String cssclass) {
String oldval = e.getAttribute(SVGConstants.SVG_CLASS_ATTRIBUTE);
if(oldval == null) {
return;
}
String[] classes = oldval.split(" ");
if(classes.length == 1) {
if(cssclass.equals(classes[0])) {
e.removeAttribute(SVGConstants.SVG_CLASS_ATTRIBUTE);
}
}
else if(classes.length == 2) {
if(cssclass.equals(classes[0])) {
if(cssclass.equals(classes[1])) {
e.removeAttribute(SVGConstants.SVG_CLASS_ATTRIBUTE);
}
else {
e.setAttribute(SVGConstants.SVG_CLASS_ATTRIBUTE, classes[1]);
}
}
else if(cssclass.equals(classes[1])) {
e.setAttribute(SVGConstants.SVG_CLASS_ATTRIBUTE, classes[0]);
}
}
else {
StringBuilder joined = new StringBuilder();
for(String c : classes) {
if(!c.equals(cssclass)) {
if(joined.length() > 0) {
joined.append(' ');
}
joined.append(c);
}
}
e.setAttribute(SVGConstants.SVG_CLASS_ATTRIBUTE, joined.toString());
}
}
/**
* Make a new CSS style element for the given Document.
*
* @param document document (factory)
* @return new CSS style element.
*/
public static Element makeStyleElement(Document document) {
Element style = SVGUtil.svgElement(document, SVGConstants.SVG_STYLE_TAG);
style.setAttribute(SVGConstants.SVG_TYPE_ATTRIBUTE, SVGConstants.CSS_MIME_TYPE);
return style;
}
/**
* Create a SVG rectangle element.
*
* @param document document to create in (factory)
* @param x X coordinate
* @param y Y coordinate
* @param w Width
* @param h Height
* @return new element
*/
public static Element svgRect(Document document, double x, double y, double w, double h) {
Element rect = SVGUtil.svgElement(document, SVGConstants.SVG_RECT_TAG);
SVGUtil.setAtt(rect, SVGConstants.SVG_X_ATTRIBUTE, x);
SVGUtil.setAtt(rect, SVGConstants.SVG_Y_ATTRIBUTE, y);
SVGUtil.setAtt(rect, SVGConstants.SVG_WIDTH_ATTRIBUTE, w);
SVGUtil.setAtt(rect, SVGConstants.SVG_HEIGHT_ATTRIBUTE, h);
return rect;
}
/**
* Create a SVG circle element.
*
* @param document document to create in (factory)
* @param cx center X
* @param cy center Y
* @param r radius
* @return new element
*/
public static Element svgCircle(Document document, double cx, double cy, double r) {
Element circ = SVGUtil.svgElement(document, SVGConstants.SVG_CIRCLE_TAG);
SVGUtil.setAtt(circ, SVGConstants.SVG_CX_ATTRIBUTE, cx);
SVGUtil.setAtt(circ, SVGConstants.SVG_CY_ATTRIBUTE, cy);
SVGUtil.setAtt(circ, SVGConstants.SVG_R_ATTRIBUTE, r);
return circ;
}
/**
* Create a SVG line element. Do not confuse this with path elements.
*
* @param document document to create in (factory)
* @param x1 first point x
* @param y1 first point y
* @param x2 second point x
* @param y2 second point y
* @return new element
*/
public static Element svgLine(Document document, double x1, double y1, double x2, double y2) {
Element line = SVGUtil.svgElement(document, SVGConstants.SVG_LINE_TAG);
SVGUtil.setAtt(line, SVGConstants.SVG_X1_ATTRIBUTE, x1);
SVGUtil.setAtt(line, SVGConstants.SVG_Y1_ATTRIBUTE, y1);
SVGUtil.setAtt(line, SVGConstants.SVG_X2_ATTRIBUTE, x2);
SVGUtil.setAtt(line, SVGConstants.SVG_Y2_ATTRIBUTE, y2);
return line;
}
/**
* Create a SVG text element.
*
* @param document document to create in (factory)
* @param x first point x
* @param y first point y
* @param text Content of text element.
* @return New text element.
*/
public static Element svgText(Document document, double x, double y, String text) {
Element elem = SVGUtil.svgElement(document, SVGConstants.SVG_TEXT_TAG);
SVGUtil.setAtt(elem, SVGConstants.SVG_X_ATTRIBUTE, x);
SVGUtil.setAtt(elem, SVGConstants.SVG_Y_ATTRIBUTE, y);
elem.setTextContent(text);
return elem;
}
/**
* Draw a simple "please wait" icon (in-progress) as placeholder for running
* renderings.
*
* @param document Document.
* @param x Left
* @param y Top
* @param w Width
* @param h Height
* @return New element (currently a {@link SVGConstants#SVG_PATH_TAG})
*/
public static Element svgWaitIcon(Document document, double x, double y, double w, double h) {
Element g = SVGUtil.svgElement(document, SVGConstants.SVG_G_TAG);
setAtt(g, SVGConstants.SVG_TRANSFORM_ATTRIBUTE, "translate(" + x + " " + y + ") scale(" + w + " " + h + ")");
Element thro = SVGUtil.svgElement(document, SVGConstants.SVG_PATH_TAG);
setAtt(thro, SVGConstants.SVG_D_ATTRIBUTE, THROBBER_PATH);
setStyle(thro, THROBBER_STYLE);
Element anim = SVGUtil.svgElement(document, SVGConstants.SVG_ANIMATE_TRANSFORM_TAG);
setAtt(anim, SVGConstants.SVG_ATTRIBUTE_NAME_ATTRIBUTE, SVGConstants.SVG_TRANSFORM_ATTRIBUTE);
setAtt(anim, SVGConstants.SVG_ATTRIBUTE_TYPE_ATTRIBUTE, "XML");
setAtt(anim, SVGConstants.SVG_TYPE_ATTRIBUTE, SVGConstants.SVG_ROTATE_ATTRIBUTE);
setAtt(anim, SVGConstants.SVG_FROM_ATTRIBUTE, "0 .5 .5");
setAtt(anim, SVGConstants.SVG_TO_ATTRIBUTE, "360 .5 .5");
setAtt(anim, SVGConstants.SVG_BEGIN_ATTRIBUTE, fmt(Math.random() * 2) + "s");
setAtt(anim, SVGConstants.SVG_DUR_ATTRIBUTE, "2s");
setAtt(anim, SVGConstants.SVG_REPEAT_COUNT_ATTRIBUTE, "indefinite");
setAtt(anim, SVGConstants.SVG_FILL_ATTRIBUTE, "freeze");
thro.appendChild(anim);
g.appendChild(thro);
return g;
}
/**
* Convert a color name from SVG syntax to an AWT color object.
*
* @param str Color name
* @return Color value
*/
public static Color stringToColor(String str) {
int icol = SVG_COLOR_NAMES.get(str.toLowerCase());
if(icol != NO_VALUE) {
return new Color(icol, false);
}
return colorLookupStylesheet.stringToColor(str);
}
/**
* Convert a color name from an AWT color object to CSS syntax
*
* Note: currently only RGB (from ARGB order) are supported.
*
* @param col Color value
* @return Color string
*/
public static String colorToString(Color col) {
return colorToString(col.getRGB());
}
/**
* Convert a color name from an integer RGB color to CSS syntax
*
* Note: currently only RGB (from ARGB order) are supported. The alpha channel
* will be ignored.
*
* @param col Color value
* @return Color string
*/
public static String colorToString(int col) {
final char[] buf = new char[] { '#', 'X', 'X', 'X', 'X', 'X', 'X' };
for(int i = 6; i > 0; i--) {
final int v = (col & 0xF);
buf[i] = (char) ((v < 10) ? ('0' + v) : ('a' + v - 10));
col >>>= 4;
}
return new String(buf);
}
/**
* Make a transform string to add margins
*
* @param owidth Width of outer (embedding) canvas
* @param oheight Height of outer (embedding) canvas
* @param iwidth Width of inner (embedded) canvas
* @param iheight Height of inner (embedded) canvas
* @param lmargin Left margin (in inner canvas' units)
* @param tmargin Top margin (in inner canvas' units)
* @param rmargin Right margin (in inner canvas' units)
* @param bmargin Bottom margin (in inner canvas' units)
* @return Transform string
*/
public static String makeMarginTransform(double owidth, double oheight, double iwidth, double iheight, double lmargin, double tmargin, double rmargin, double bmargin) {
double swidth = iwidth + lmargin + rmargin;
double sheight = iheight + tmargin + bmargin;
double scale = Math.max(swidth / owidth, sheight / oheight);
double offx = (scale * owidth - swidth) * .5 + lmargin;
double offy = (scale * oheight - sheight) * .5 + tmargin;
return "scale(" + fmt(1 / scale) + ") translate(" + fmt(offx) + " " + fmt(offy) + ")";
}
/**
* Make a transform string to add margins
*
* @param owidth Width of outer (embedding) canvas
* @param oheight Height of outer (embedding) canvas
* @param iwidth Width of inner (embedded) canvas
* @param iheight Height of inner (embedded) canvas
* @param xmargin Left and right margin (in inner canvas' units)
* @param ymargin Top and bottom margin (in inner canvas' units)
* @return Transform string
*/
public static String makeMarginTransform(double owidth, double oheight, double iwidth, double iheight, double xmargin, double ymargin) {
return makeMarginTransform(owidth, oheight, iwidth, iheight, xmargin, ymargin, xmargin, ymargin);
}
/**
* Make a transform string to add margins
*
* @param owidth Width of outer (embedding) canvas
* @param oheight Height of outer (embedding) canvas
* @param iwidth Width of inner (embedded) canvas
* @param iheight Height of inner (embedded) canvas
* @param margin Margin (in inner canvas' units)
* @return Transform string
*/
public static String makeMarginTransform(double owidth, double oheight, double iwidth, double iheight, double margin) {
return makeMarginTransform(owidth, oheight, iwidth, iheight, margin, margin, margin, margin);
}
/**
* Convert the coordinates of an DOM Event from screen into element
* coordinates.
*
* @param doc Document context
* @param tag Element containing the coordinate system
* @param evt Event to interpret
* @return coordinates
*/
public static SVGPoint elementCoordinatesFromEvent(Document doc, Element tag, Event evt) {
try {
DOMMouseEvent gnme = (DOMMouseEvent) evt;
SVGMatrix mat = ((SVGLocatable) tag).getScreenCTM();
SVGMatrix imat = mat.inverse();
SVGPoint cPt = ((SVGDocument) doc).getRootElement().createSVGPoint();
cPt.setX(gnme.getClientX());
cPt.setY(gnme.getClientY());
return cPt.matrixTransform(imat);
}
catch(Exception e) {
LoggingUtil.warning("Error getting coordinates from SVG event.", e);
return null;
}
}
/**
* Remove last child of an element, when present
*
* @param tag Parent
*/
public static void removeLastChild(Element tag) {
final Node last = tag.getLastChild();
if(last != null) {
tag.removeChild(last);
}
}
/**
* Remove an element from its parent, if defined.
*
* @param elem Element to remove
*/
public static void removeFromParent(Element elem) {
if(elem != null && elem.getParentNode() != null) {
elem.getParentNode().removeChild(elem);
}
}
/**
* Create a circle segment.
*
* @param svgp Plot to draw to
* @param centerx Center X position
* @param centery Center Y position
* @param angleStart Starting angle
* @param angleDelta Angle delta
* @param innerRadius inner radius
* @param outerRadius outer radius
* @return SVG element representing this circle segment
*/
public static Element svgCircleSegment(SVGPlot svgp, double centerx, double centery, double angleStart, double angleDelta, double innerRadius, double outerRadius) {
double sin1st = Math.sin(angleStart);
double cos1st = MathUtil.sinToCos(angleStart, sin1st);
double sin2nd = Math.sin(angleStart + angleDelta);
double cos2nd = MathUtil.sinToCos(angleStart + angleDelta, sin2nd);
double inner1stx = centerx + (innerRadius * sin1st);
double inner1sty = centery - (innerRadius * cos1st);
double outer1stx = centerx + (outerRadius * sin1st);
double outer1sty = centery - (outerRadius * cos1st);
double inner2ndx = centerx + (innerRadius * sin2nd);
double inner2ndy = centery - (innerRadius * cos2nd);
double outer2ndx = centerx + (outerRadius * sin2nd);
double outer2ndy = centery - (outerRadius * cos2nd);
double largeArc = 0;
if(angleDelta >= Math.PI) {
largeArc = 1;
}
SVGPath path = new SVGPath(inner1stx, inner1sty);
path.lineTo(outer1stx, outer1sty);
path.ellipticalArc(outerRadius, outerRadius, 0, largeArc, 1, outer2ndx, outer2ndy);
path.lineTo(inner2ndx, inner2ndy);
if(innerRadius > 0) {
path.ellipticalArc(innerRadius, innerRadius, 0, largeArc, 0, inner1stx, inner1sty);
}
return path.makeElement(svgp);
}
}
UpdateRunner.java 0000664 0000000 0000000 00000010142 12657057427 0034071 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/svg package de.lmu.ifi.dbs.elki.visualization.svg;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.concurrent.ConcurrentLinkedQueue;
import de.lmu.ifi.dbs.elki.logging.LoggingUtil;
/**
* Class to handle updates to an SVG plot, in particular when used in an Apache
* Batik UI.
*
* @author Erich Schubert
* @since 0.3
*
* @apiviz.has Runnable
* @apiviz.uses UpdateSynchronizer
*/
public class UpdateRunner {
/**
* Owner/Synchronization object
*/
private Object sync;
/**
* The queue of pending updates
*/
final private ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue<>();
/**
* Synchronizer that can block events from being executed right away.
*/
private UpdateSynchronizer synchronizer = null;
/**
* Construct a new update handler
*
* @param sync Object to synchronize on
*/
protected UpdateRunner(Object sync) {
this.sync = sync;
}
/**
* Add a new update to run at any appropriate time.
*
* @param r New runnable to perform the update
*/
public void invokeLater(Runnable r) {
queue.add(r);
synchronized(this) {
if(synchronizer == null) {
runQueue();
}
else {
synchronizer.activate();
}
}
}
/**
* Run the processing queue now. This should usually be only invoked by the
* UpdateSynchronizer
*/
public void runQueue() {
synchronized(sync) {
while(!queue.isEmpty()) {
Runnable r = queue.poll();
if(r != null) {
try {
r.run();
}
catch(Exception e) {
// Alternatively, we could allow the specification of exception
// handlers for each runnable in the API. For now we'll just log.
// TODO: handle exceptions here better!
LoggingUtil.exception(e);
}
}
else {
LoggingUtil.warning("Tried to run a 'null' Object.");
}
}
}
}
/**
* Clear queue. For shutdown!
*/
public synchronized void clear() {
queue.clear();
}
/**
* Check whether the queue is empty.
*
* @return queue status
*/
public boolean isEmpty() {
return queue.isEmpty();
}
/**
* Set a new update synchronizer.
*
* @param newsync Update synchronizer
*/
public synchronized void synchronizeWith(UpdateSynchronizer newsync) {
// LoggingUtil.warning("Synchronizing: " + sync + " " + newsync, new
// Throwable());
if(synchronizer == newsync) {
LoggingUtil.warning("Double-synced to the same plot!", new Throwable());
return;
}
if(synchronizer != null) {
LoggingUtil.warning("Attempting to synchronize to more than one synchronizer.");
return;
}
synchronizer = newsync;
newsync.addUpdateRunner(this);
}
/**
* Remove an update synchronizer
*
* @param oldsync Update synchronizer to remove
*/
public synchronized void unsynchronizeWith(UpdateSynchronizer oldsync) {
if(synchronizer == null) {
LoggingUtil.warning("Warning: was not synchronized.");
return;
}
if(synchronizer != oldsync) {
LoggingUtil.warning("Warning: was synchronized differently!");
return;
}
// LoggingUtil.warning("Unsynchronizing: " + sync + " " + oldsync);
synchronizer = null;
runQueue();
}
} UpdateSynchronizer.java 0000664 0000000 0000000 00000002446 12657057427 0035325 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/svg package de.lmu.ifi.dbs.elki.visualization.svg;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
/**
* API to synchronize updates
*
* @author Erich Schubert
* @since 0.3
*
* @apiviz.has UpdateRunner
*/
public interface UpdateSynchronizer {
/**
* This method is called whenever a new pending event was added.
*/
void activate();
/**
* Set an update runner to use.
*
* @param updateRunner
*/
void addUpdateRunner(UpdateRunner updateRunner);
} VoronoiDraw.java 0000664 0000000 0000000 00000012765 12657057427 0033743 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/svg package de.lmu.ifi.dbs.elki.visualization.svg;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.List;
import de.lmu.ifi.dbs.elki.math.geometry.SweepHullDelaunay2D;
import de.lmu.ifi.dbs.elki.math.geometry.SweepHullDelaunay2D.Triangle;
import de.lmu.ifi.dbs.elki.math.linearalgebra.VMath;
import de.lmu.ifi.dbs.elki.visualization.projections.CanvasSize;
import de.lmu.ifi.dbs.elki.visualization.projections.Projection2D;
/**
* Draw the Voronoi cells
*
* @author Robert Rödler
* @author Erich Schubert
* @since 0.5.0
*
* @apiviz.uses de.lmu.ifi.dbs.elki.math.geometry.SweepHullDelaunay2D.Triangle
* @apiviz.uses Projection2D
*/
public class VoronoiDraw {
/**
* Draw the Delaunay triangulation.
*
* @param proj Projection
* @param delaunay Triangulation
* @param means Means
* @return Path
*/
public static SVGPath drawDelaunay(Projection2D proj, List delaunay, List means) {
final SVGPath path = new SVGPath();
for(SweepHullDelaunay2D.Triangle del : delaunay) {
path.moveTo(proj.fastProjectDataToRenderSpace(means.get(del.a)));
path.drawTo(proj.fastProjectDataToRenderSpace(means.get(del.b)));
path.drawTo(proj.fastProjectDataToRenderSpace(means.get(del.c)));
path.close();
}
return path;
}
/**
* Draw a Voronoi diagram
*
* @param proj Projection
* @param delaunay Delaunay triangulation
* @param means Cluster means
* @return SVG path
*/
public static SVGPath drawVoronoi(Projection2D proj, List delaunay, List means) {
final SVGPath path = new SVGPath();
CanvasSize viewport = proj.estimateViewport();
for(int i = 0; i < delaunay.size(); i++) {
SweepHullDelaunay2D.Triangle del = delaunay.get(i);
final double[] projcx = proj.fastProjectDataToRenderSpace(del.m.getArrayRef());
if(del.ab > i) {
Triangle oth = delaunay.get(del.ab);
path.moveTo(projcx);
path.drawTo(proj.fastProjectDataToRenderSpace(oth.m.getArrayRef()));
}
else if(del.ab < 0) {
double[] dirv = VMath.minus(means.get(del.a), means.get(del.b));
VMath.rotate90Equals(dirv);
double[] dir = proj.fastProjectRelativeDataToRenderSpace(dirv);
final double factor = viewport.continueToMargin(projcx, dir);
if(factor > 0) {
path.moveTo(projcx);
path.relativeLineTo(factor * dir[0], factor * dir[1]);
}
}
if(del.bc > i) {
Triangle oth = delaunay.get(del.bc);
path.moveTo(projcx);
path.drawTo(proj.fastProjectDataToRenderSpace(oth.m.getArrayRef()));
}
else if(del.bc < 0) {
double[] dirv = VMath.minus(means.get(del.b), means.get(del.c));
VMath.rotate90Equals(dirv);
double[] dir = proj.fastProjectRelativeDataToRenderSpace(dirv);
final double factor = viewport.continueToMargin(projcx, dir);
if(factor > 0) {
path.moveTo(projcx);
path.relativeLineTo(factor * dir[0], factor * dir[1]);
}
}
if(del.ca > i) {
Triangle oth = delaunay.get(del.ca);
path.moveTo(projcx);
path.drawTo(proj.fastProjectDataToRenderSpace(oth.m.getArrayRef()));
}
else if(del.ca < 0) {
double[] dirv = VMath.minus(means.get(del.c), means.get(del.a));
VMath.rotate90Equals(dirv);
double[] dir = proj.fastProjectRelativeDataToRenderSpace(dirv);
final double factor = viewport.continueToMargin(projcx, dir);
if(factor > 0) {
path.moveTo(projcx);
path.relativeLineTo(factor * dir[0], factor * dir[1]);
}
}
}
return path;
}
/**
* Fake Voronoi diagram. For two means only
*
* @param proj Projection
* @param means Mean vectors
* @return SVG path
*/
public static SVGPath drawFakeVoronoi(Projection2D proj, List means) {
CanvasSize viewport = proj.estimateViewport();
final SVGPath path = new SVGPath();
// Difference
final double[] dirv = VMath.minus(means.get(1), means.get(0));
VMath.rotate90Equals(dirv);
double[] dir = proj.fastProjectRelativeDataToRenderSpace(dirv);
// Mean
final double[] mean = VMath.plus(means.get(0), means.get(1));
VMath.timesEquals(mean, 0.5);
double[] projmean = proj.fastProjectDataToRenderSpace(mean);
double factor = viewport.continueToMargin(projmean, dir);
path.moveTo(projmean[0] + factor * dir[0], projmean[1] + factor * dir[1]);
// Inverse direction:
dir[0] *= -1;
dir[1] *= -1;
factor = viewport.continueToMargin(projmean, dir);
path.drawTo(projmean[0] + factor * dir[0], projmean[1] + factor * dir[1]);
return path;
}
} package-info.java 0000775 0000000 0000000 00000001765 12657057427 0034017 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/svg /**
*
Base SVG functionality (generation, markers, thumbnails, export, ...).
*
*/
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.lmu.ifi.dbs.elki.visualization.svg; elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/ 0000775 0000000 0000000 00000000000 12657057427 0032454 5 ustar 00root root 0000000 0000000 AbstractVisFactory.java 0000664 0000000 0000000 00000005005 12657057427 0037015 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers package de.lmu.ifi.dbs.elki.visualization.visualizers;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.logging.LoggingUtil;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.gui.VisualizationPlot;
import de.lmu.ifi.dbs.elki.visualization.projections.Projection;
import de.lmu.ifi.dbs.elki.visualization.visualizers.thumbs.ThumbnailVisualization;
/**
* Abstract superclass for Visualizers (aka: Visualization Factories).
*
* @author Remigius Wojdanowski
* @since 0.4.0
*
* @apiviz.uses ThumbnailVisualization oneway - - «create»
* @apiviz.excludeSubtypes
*/
public abstract class AbstractVisFactory implements VisFactory {
/**
* Constructor.
*/
protected AbstractVisFactory() {
super();
}
@Override
public Visualization makeVisualizationOrThumbnail(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj, int thumbsize) {
if(width <= 0 || height <= 0) {
LoggingUtil.warning("Cannot generate visualization of 0 size.", new Throwable());
return null;
}
if(allowThumbnails(task)) {
return new ThumbnailVisualization(this, task, plot, width, height, proj, thumbsize);
}
return makeVisualization(task, plot, width, height, proj);
}
@Override
abstract public Visualization makeVisualization(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj);
/**
* Test whether to do a thumbnail or a full rendering.
*
* Override this with "false" to disable thumbnails!
*
* @param task Task requested
*/
public boolean allowThumbnails(VisualizationTask task) {
return true;
}
} AbstractVisualization.java 0000664 0000000 0000000 00000013423 12657057427 0037570 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers package de.lmu.ifi.dbs.elki.visualization.visualizers;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.w3c.dom.Element;
import de.lmu.ifi.dbs.elki.database.datastore.DataStoreEvent;
import de.lmu.ifi.dbs.elki.database.datastore.DataStoreListener;
import de.lmu.ifi.dbs.elki.result.Result;
import de.lmu.ifi.dbs.elki.result.ResultListener;
import de.lmu.ifi.dbs.elki.result.SamplingResult;
import de.lmu.ifi.dbs.elki.result.SelectionResult;
import de.lmu.ifi.dbs.elki.visualization.VisualizationItem;
import de.lmu.ifi.dbs.elki.visualization.VisualizationListener;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.gui.VisualizationPlot;
import de.lmu.ifi.dbs.elki.visualization.style.StylingPolicy;
/**
* Abstract base class for visualizations.
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.excludeSubtypes
*/
public abstract class AbstractVisualization implements Visualization, ResultListener, VisualizationListener, DataStoreListener {
/**
* The visualization task we do.
*/
protected final VisualizationTask task;
/**
* Our context
*/
protected final VisualizerContext context;
/**
* The plot we are attached to
*/
protected final VisualizationPlot svgp;
/**
* Layer storage
*/
protected Element layer;
/**
* Width
*/
private double width;
/**
* Height
*/
private double height;
/**
* Constructor.
*
* @param task Visualization task
* @param plot Plot to draw to
* @param width Embedding width
* @param height Embedding height
*/
public AbstractVisualization(VisualizationTask task, VisualizationPlot plot, double width, double height) {
super();
this.task = task;
this.context = task.getContext();
this.svgp = plot;
this.width = width;
this.height = height;
this.layer = null;
// Note: we do not auto-add listeners, as we don't know what kind of
// listeners a visualizer needs, and the visualizer might need to do some
// initialization first
}
/**
* Add the listeners according to the mask.
*/
protected void addListeners() {
// Listen for result changes, including the one we monitor
context.addResultListener(this);
context.addVisualizationListener(this);
// Listen for database events only when needed.
if(task.updateOnAny(VisualizationTask.ON_DATA)) {
context.addDataStoreListener(this);
}
}
@Override
public void destroy() {
// Always unregister listeners, as this is easy to forget otherwise
// TODO: remove destroy() overrides that are redundant?
context.removeResultListener(this);
context.removeVisualizationListener(this);
context.removeDataStoreListener((DataStoreListener) this);
}
@Override
public Element getLayer() {
if(layer == null) {
incrementalRedraw();
}
return layer;
}
/**
* Get the width
*
* @return the width
*/
protected double getWidth() {
return width;
}
/**
* Get the height
*
* @return the height
*/
protected double getHeight() {
return height;
}
/**
* Redraw the visualization (maybe incremental).
*
* Optional - by default, it will do a full redraw, which often is faster!
*/
@Override
public void incrementalRedraw() {
Element oldcontainer = null;
if(layer != null && layer.hasChildNodes()) {
oldcontainer = layer;
// Shallow clone:
layer = (Element) layer.cloneNode(false);
}
fullRedraw();
if(oldcontainer != null && oldcontainer.getParentNode() != null) {
oldcontainer.getParentNode().replaceChild(layer, oldcontainer);
}
}
@Override
public abstract void fullRedraw();
@Override
public void resultAdded(Result child, Result parent) {
// Ignore by default
}
@Override
public void resultChanged(Result current) {
// Default is to redraw when the result we are attached to changed.
if(task.getResult() == current) {
svgp.requestRedraw(this.task, this);
return;
}
if(task.updateOnAny(VisualizationTask.ON_SELECTION) && current instanceof SelectionResult) {
svgp.requestRedraw(this.task, this);
return;
}
if(task.updateOnAny(VisualizationTask.ON_SAMPLE) && current instanceof SamplingResult) {
svgp.requestRedraw(this.task, this);
return;
}
}
@Override
public void resultRemoved(Result child, Result parent) {
// Ignore by default.
// TODO: auto-remove if parent result is removed?
}
@Override
public void visualizationChanged(VisualizationItem item) {
if(task == item || task.getResult() == item) {
svgp.requestRedraw(this.task, this);
return;
}
if(task.updateOnAny(VisualizationTask.ON_STYLEPOLICY) && item instanceof StylingPolicy) {
svgp.requestRedraw(this.task, this);
return;
}
}
@Override
public void contentChanged(DataStoreEvent e) {
svgp.requestRedraw(this.task, this);
}
} StaticVisualizationInstance.java 0000664 0000000 0000000 00000003565 12657057427 0040747 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers package de.lmu.ifi.dbs.elki.visualization.visualizers;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.w3c.dom.Element;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.gui.VisualizationPlot;
/**
* Static visualization
*
* @author Erich Schubert
* @since 0.4.0
*/
public class StaticVisualizationInstance extends AbstractVisualization {
/**
* Unchanging precomputed visualization.
*
* @param task Task to visualize
* @param plot Plot to draw to
* @param width Embedding width
* @param height Embedding height
* @param element Element containing the resulting visualization
*/
public StaticVisualizationInstance(VisualizationTask task, VisualizationPlot plot, double width, double height, Element element) {
super(task, plot, width, height);
this.layer = element;
}
@Override
public void incrementalRedraw() {
// Do nothing - we keep our static layer
}
@Override
public void fullRedraw() {
// Do nothing - we keep our static layer
}
}
VisFactory.java 0000664 0000000 0000000 00000005334 12657057427 0035336 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers package de.lmu.ifi.dbs.elki.visualization.visualizers;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.visualization.VisualizationProcessor;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.gui.VisualizationPlot;
import de.lmu.ifi.dbs.elki.visualization.projections.Projection;
/**
* Defines the requirements for a visualizer.
* Note: Any implementation is supposed to provide a constructor without
* parameters (default constructor) to be used for parameterization.
*
* @author Remigius Wojdanowski
* @since 0.3
*
* @apiviz.landmark
* @apiviz.stereotype factory
* @apiviz.uses Visualization - - «create»
* @apiviz.uses VisualizationTask - - «create»
*/
public interface VisFactory extends VisualizationProcessor {
/**
* Add visualizers for the given result (tree) to the context.
*
* @param context Visualization context
* @param start Result to process
*/
@Override
void processNewResult(VisualizerContext context, Object start);
/**
* Produce a visualization instance for the given task
*
* @param task Visualization task
* @param plot Plot
* @param width Width
* @param height Height
* @param proj Projection
* @return Visualization
*/
Visualization makeVisualization(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj);
/**
* Produce a visualization instance for the given task that may use thumbnails
*
* @param task Visualization task
* @param plot Plot
* @param width Width
* @param height Height
* @param proj Projection
* @param thumbsize Thumbnail size
* @return Visualization
*/
Visualization makeVisualizationOrThumbnail(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj, int thumbsize);
} Visualization.java 0000664 0000000 0000000 00000003146 12657057427 0036105 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers package de.lmu.ifi.dbs.elki.visualization.visualizers;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.w3c.dom.Element;
/**
* Base class for a materialized Visualization.
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.landmark
* @apiviz.has Element oneway
*/
public interface Visualization {
/**
* Get the SVG layer of the given visualization.
*
* @return layer
*/
Element getLayer();
/**
* Request an update of the visualization.
*/
void incrementalRedraw();
/**
* Request a full redrawing of the visualization.
*/
void fullRedraw();
/**
* Destroy the visualization. Called after the elements have been removed from
* the document.
*
* Implementations should remove their listeners etc.
*/
void destroy();
} 0000775 0000000 0000000 00000000000 12657057427 0034035 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/actions ClusterStyleAction.java 0000664 0000000 0000000 00000007374 12657057427 0040513 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/actions package de.lmu.ifi.dbs.elki.visualization.visualizers.actions;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.data.Clustering;
import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.Hierarchy;
import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException;
import de.lmu.ifi.dbs.elki.visualization.VisualizationMenuAction;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTree;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.gui.VisualizationPlot;
import de.lmu.ifi.dbs.elki.visualization.projections.Projection;
import de.lmu.ifi.dbs.elki.visualization.style.ClusterStylingPolicy;
import de.lmu.ifi.dbs.elki.visualization.style.StylingPolicy;
import de.lmu.ifi.dbs.elki.visualization.visualizers.AbstractVisFactory;
import de.lmu.ifi.dbs.elki.visualization.visualizers.Visualization;
/**
* Actions to use clusterings for styling.
*
* @author Erich Schubert
* @since 0.7.0
*/
public class ClusterStyleAction extends AbstractVisFactory {
/**
* Constructor.
*/
public ClusterStyleAction() {
super();
}
@Override
public void processNewResult(final VisualizerContext context, Object start) {
Hierarchy.Iter> it = VisualizationTree.filterResults(context, start, Clustering.class);
for(; it.valid(); it.advance()) {
final Clustering> c = it.get();
Hierarchy.Iter it2 = VisualizationTree.filter(context, c, SetStyleAction.class);
if(it2.valid()) {
continue; // There already is a style button.
}
context.addVis(c, new SetStyleAction(c, context));
}
}
@Override
public Visualization makeVisualization(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj) {
throw new AbortException("Should never be called.");
}
/**
* Action to use a clustering as {@link ClusterStylingPolicy}.
*
* @author Erich Schubert
*/
private static final class SetStyleAction implements VisualizationMenuAction {
/**
* Clustering to use
*/
private final Clustering> c;
/**
* Visualization context.
*/
private final VisualizerContext context;
/**
* Constructor.
*
* @param c Clustering
* @param context Context
*/
private SetStyleAction(Clustering> c, VisualizerContext context) {
this.c = c;
this.context = context;
}
@Override
public void activate() {
context.setStylingPolicy(new ClusterStylingPolicy(c, context.getStyleLibrary()));
}
@Override
public String getMenuName() {
return "Use as Styling Policy";
}
@Override
public boolean enabled() {
StylingPolicy sp = context.getStylingPolicy();
if(!(sp instanceof ClusterStylingPolicy)) {
return true;
}
return ((ClusterStylingPolicy) sp).getClustering() != c;
}
}
}
package-info.java 0000664 0000000 0000000 00000001777 12657057427 0037240 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/actions /**
* Action-only "visualizers" that only produce menu entries.
*/
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.lmu.ifi.dbs.elki.visualization.visualizers.actions; 0000775 0000000 0000000 00000000000 12657057427 0034372 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/histogram AbstractHistogramVisualization.java 0000664 0000000 0000000 00000004457 12657057427 0043452 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/histogram package de.lmu.ifi.dbs.elki.visualization.visualizers.histogram;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.result.Result;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.gui.VisualizationPlot;
import de.lmu.ifi.dbs.elki.visualization.projections.Projection;
import de.lmu.ifi.dbs.elki.visualization.projections.Projection1D;
import de.lmu.ifi.dbs.elki.visualization.visualizers.AbstractVisualization;
/**
* One-dimensional projected visualization.
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.landmark
* @apiviz.has Projection1D
*/
public abstract class AbstractHistogramVisualization extends AbstractVisualization {
/**
* The current projection
*/
final protected Projection1D proj;
/**
* Constructor.
*
* @param task Visualization task
* @param plot Plot to draw to
* @param width Embedding width
* @param height Embedding height
* @param proj Projection
*/
public AbstractHistogramVisualization(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj) {
super(task, plot, width, height);
assert(proj instanceof Projection1D) : "Visualizer attached to wrong projection!";
this.proj = (Projection1D) proj;
}
@Override
public void resultChanged(Result current) {
super.resultChanged(current);
if(proj != null && current == proj) {
svgp.requestRedraw(this.task, this);
return;
}
}
} ColoredHistogramVisualizer.java 0000664 0000000 0000000 00000040064 12657057427 0042564 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/histogram package de.lmu.ifi.dbs.elki.visualization.visualizers.histogram;
import java.util.Arrays;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
import de.lmu.ifi.dbs.elki.data.DoubleVector;
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
import de.lmu.ifi.dbs.elki.database.relation.Relation;
import de.lmu.ifi.dbs.elki.database.relation.RelationUtil;
import de.lmu.ifi.dbs.elki.logging.LoggingUtil;
import de.lmu.ifi.dbs.elki.math.DoubleMinMax;
import de.lmu.ifi.dbs.elki.math.scales.LinearScale;
import de.lmu.ifi.dbs.elki.result.ResultUtil;
import de.lmu.ifi.dbs.elki.result.SamplingResult;
import de.lmu.ifi.dbs.elki.utilities.datastructures.histogram.DoubleArrayStaticHistogram;
import de.lmu.ifi.dbs.elki.utilities.exceptions.ObjectNotFoundException;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.CommonConstraints;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.Flag;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.IntParameter;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTree;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.colors.ColorLibrary;
import de.lmu.ifi.dbs.elki.visualization.css.CSSClass;
import de.lmu.ifi.dbs.elki.visualization.css.CSSClassManager.CSSNamingConflict;
import de.lmu.ifi.dbs.elki.visualization.gui.VisualizationPlot;
import de.lmu.ifi.dbs.elki.visualization.projections.Projection;
import de.lmu.ifi.dbs.elki.visualization.projector.HistogramProjector;
import de.lmu.ifi.dbs.elki.visualization.style.ClassStylingPolicy;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.style.StylingPolicy;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGPath;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGPlot;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGSimpleLinearAxis;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
import de.lmu.ifi.dbs.elki.visualization.visualizers.AbstractVisFactory;
import de.lmu.ifi.dbs.elki.visualization.visualizers.Visualization;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
/**
* Generates a SVG-Element containing a histogram representing the distribution
* of the database's objects.
*
* @author Remigius Wojdanowski
* @author Erich Schubert
* @since 0.3
*
* @apiviz.stereotype factory
* @apiviz.uses Instance oneway - - «create»
*/
public class ColoredHistogramVisualizer extends AbstractVisFactory {
/**
* Name for this visualizer.
*/
private static final String CNAME = "Histograms";
/**
* Settings
*/
protected Parameterizer settings;
/**
* Number of bins to use in histogram.
*/
private static final int DEFAULT_BINS = 80;
/**
* Constructor.
*
* @param settings Settings
*/
public ColoredHistogramVisualizer(Parameterizer settings) {
super();
this.settings = settings;
}
@Override
public Visualization makeVisualization(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj) {
return new Instance(task, plot, width, height, proj);
}
@Override
public void processNewResult(VisualizerContext context, Object start) {
VisualizationTree.findNew(context, start, HistogramProjector.class, //
new VisualizationTree.Handler1>() {
@Override
public void process(VisualizerContext context, HistogramProjector> p) {
// register self
final VisualizationTask task = new VisualizationTask(CNAME, context, p, p.getRelation(), ColoredHistogramVisualizer.this);
task.level = VisualizationTask.LEVEL_DATA;
task.addUpdateFlags(VisualizationTask.ON_DATA | VisualizationTask.ON_STYLEPOLICY);
context.addVis(p, task);
}
});
}
@Override
public boolean allowThumbnails(VisualizationTask task) {
// Don't use thumbnails
return false;
}
/**
* Instance
*
* @author Remigius Wojdanowski
*
* @apiviz.has NumberVector oneway - - visualizes
*
* @param Type of the DatabaseObject being visualized.
*/
// FIXME: cache histogram instead of recomputing it?
public class Instance extends AbstractHistogramVisualization {
/**
* Generic tag to indicate the type of element. Used in IDs, CSS-Classes
* etc.
*/
public static final String BIN = "bin";
/**
* The database we visualize
*/
private Relation relation;
/**
* Sampling result
*/
private SamplingResult sample;
/**
* Constructor.
*
* @param task Visualization task
* @param plot Plot to draw to
* @param width Embedding width
* @param height Embedding height
* @param proj Projection
*/
public Instance(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj) {
super(task, plot, width, height, proj);
this.relation = task.getRelation();
this.sample = ResultUtil.getSamplingResult(relation);
addListeners();
}
@Override
public void fullRedraw() {
StyleLibrary style = context.getStyleLibrary();
double margin = style.getSize(StyleLibrary.MARGIN);
layer = SVGUtil.svgElement(svgp.getDocument(), SVGConstants.SVG_G_TAG);
double xsize = Projection.SCALE * getWidth() / getHeight();
double ysize = Projection.SCALE;
final String transform = SVGUtil.makeMarginTransform(getWidth(), getHeight(), xsize, ysize, margin);
SVGUtil.setAtt(layer, SVGConstants.SVG_TRANSFORM_ATTRIBUTE, transform);
// Styling policy
final StylingPolicy spol = context.getStylingPolicy();
final ClassStylingPolicy cspol;
if(spol instanceof ClassStylingPolicy) {
cspol = (ClassStylingPolicy) spol;
}
else {
cspol = null;
}
// TODO also use min style?
setupCSS(svgp, (cspol != null) ? cspol.getMaxStyle() : 0);
// Create histograms
final int off = (cspol != null) ? cspol.getMinStyle() : 0;
final int numc = (cspol != null) ? (cspol.getMaxStyle() - cspol.getMinStyle()) : 0;
DoubleMinMax minmax = new DoubleMinMax();
final double frac = 1. / relation.size(); // TODO: sampling?
final int cols = numc + 1;
DoubleArrayStaticHistogram histogram = new DoubleArrayStaticHistogram(settings.bins, -.5, .5, cols);
if(cspol != null) {
for(int snum = 0; snum < numc; snum++) {
double[] inc = new double[cols];
inc[0] = frac;
inc[snum + 1] = frac;
for(DBIDIter iter = cspol.iterateClass(snum + off); iter.valid(); iter.advance()) {
if(!sample.getSample().contains(iter)) {
continue; // TODO: can we test more efficiently than this?
}
try {
double pos = proj.fastProjectDataToRenderSpace(relation.get(iter)) * Projection.INVSCALE;
histogram.increment(pos, inc);
}
catch(ObjectNotFoundException e) {
// Ignore. The object was probably deleted from the database
}
}
}
}
else {
// Actual data distribution.
double[] inc = new double[cols];
inc[0] = frac;
for(DBIDIter iditer = relation.iterDBIDs(); iditer.valid(); iditer.advance()) {
double pos = proj.fastProjectDataToRenderSpace(relation.get(iditer)) * Projection.INVSCALE;
histogram.increment(pos, inc);
}
}
// for scaling, get the maximum occurring value in the bins:
for(DoubleArrayStaticHistogram.Iter iter = histogram.iter(); iter.valid(); iter.advance()) {
for(double val : iter.getValue()) {
minmax.put(val);
}
}
LinearScale yscale = new LinearScale(0, minmax.getMax());
LinearScale xscale = new LinearScale(histogram.getCoverMinimum(), histogram.getCoverMaximum());
// Axis. TODO: Add an AxisVisualizer for this?
try {
SVGSimpleLinearAxis.drawAxis(svgp, layer, yscale, 0, ysize, 0, 0, SVGSimpleLinearAxis.LabelStyle.LEFTHAND, style);
// draw axes that are non-trivial
final int dimensionality = RelationUtil.dimensionality(relation);
final double[] vec = new double[dimensionality];
double orig = proj.fastProjectScaledToRender(vec);
for(int d = 0; d < dimensionality; d++) {
Arrays.fill(vec, 0.);
vec[d] = 1;
// projected endpoint of axis
double ax = proj.fastProjectScaledToRender(vec);
if(ax < orig || ax > orig) {
final double left = (orig / Projection.SCALE + 0.5) * xsize;
final double right = (ax / Projection.SCALE + 0.5) * xsize;
SVGSimpleLinearAxis.drawAxis(svgp, layer, proj.getScale(d), left, ysize, right, ysize, SVGSimpleLinearAxis.LabelStyle.RIGHTHAND, style);
}
}
}
catch(CSSNamingConflict e) {
LoggingUtil.exception("CSS class exception in axis class.", e);
}
// Visualizing
if(!settings.curves) {
for(DoubleArrayStaticHistogram.Iter iter = histogram.iter(); iter.valid(); iter.advance()) {
double lpos = xscale.getScaled(iter.getLeft());
double rpos = xscale.getScaled(iter.getRight());
double stack = 0.0;
final int start = numc > 0 ? 1 : 0;
for(int key = start; key < cols; key++) {
double val = yscale.getScaled(iter.getValue()[key]);
Element row = SVGUtil.svgRect(svgp.getDocument(), xsize * lpos, ysize * (1 - (val + stack)), xsize * (rpos - lpos), ysize * val);
stack = stack + val;
SVGUtil.addCSSClass(row, BIN + (off + key - 1));
layer.appendChild(row);
}
}
}
else {
double left = xscale.getScaled(histogram.getCoverMinimum());
double right = left;
SVGPath[] paths = new SVGPath[cols];
double[] lasty = new double[cols];
for(int i = 0; i < cols; i++) {
paths[i] = new SVGPath(xsize * left, ysize * 1);
lasty[i] = 0;
}
// draw histogram lines
for(DoubleArrayStaticHistogram.Iter iter = histogram.iter(); iter.valid(); iter.advance()) {
left = xscale.getScaled(iter.getLeft());
right = xscale.getScaled(iter.getRight());
for(int i = 0; i < cols; i++) {
double val = yscale.getScaled(iter.getValue()[i]);
if(lasty[i] > val || lasty[i] < val) {
paths[i].lineTo(xsize * left, ysize * (1 - lasty[i]));
paths[i].lineTo(xsize * left, ysize * (1 - val));
paths[i].lineTo(xsize * right, ysize * (1 - val));
lasty[i] = val;
}
}
}
// close and insert all lines.
for(int i = 0; i < cols; i++) {
if(lasty[i] != 0) {
paths[i].lineTo(xsize * right, ysize * (1 - lasty[i]));
}
paths[i].lineTo(xsize * right, ysize * 1);
Element elem = paths[i].makeElement(svgp);
SVGUtil.addCSSClass(elem, BIN + (off + i - 1));
layer.appendChild(elem);
}
}
svgp.updateStyleElement();
}
/**
* Generate the needed CSS classes.
*
* @param svgp Plot context
* @param numc Number of classes we need.
*/
private void setupCSS(SVGPlot svgp, int numc) {
final StyleLibrary style = context.getStyleLibrary();
ColorLibrary colors = style.getColorSet(StyleLibrary.PLOT);
CSSClass allInOne = new CSSClass(svgp, BIN + -1);
if(!settings.curves) {
allInOne.setStatement(SVGConstants.CSS_FILL_PROPERTY, SVGConstants.CSS_BLACK_VALUE);
allInOne.setStatement(SVGConstants.CSS_FILL_OPACITY_PROPERTY, 1.0);
}
else {
allInOne.setStatement(SVGConstants.CSS_STROKE_PROPERTY, SVGConstants.CSS_BLACK_VALUE);
allInOne.setStatement(SVGConstants.CSS_STROKE_WIDTH_PROPERTY, style.getLineWidth(StyleLibrary.PLOT));
allInOne.setStatement(SVGConstants.CSS_FILL_PROPERTY, SVGConstants.CSS_NONE_VALUE);
}
svgp.addCSSClassOrLogError(allInOne);
for(int clusterID = 0; clusterID < numc; clusterID++) {
CSSClass bin = new CSSClass(svgp, BIN + clusterID);
if(!settings.curves) {
bin.setStatement(SVGConstants.CSS_FILL_PROPERTY, colors.getColor(clusterID));
}
else {
bin.setStatement(SVGConstants.CSS_STROKE_PROPERTY, colors.getColor(clusterID));
bin.setStatement(SVGConstants.CSS_STROKE_WIDTH_PROPERTY, style.getLineWidth(StyleLibrary.PLOT));
bin.setStatement(SVGConstants.CSS_FILL_PROPERTY, SVGConstants.CSS_NONE_VALUE);
}
svgp.addCSSClassOrLogError(bin);
}
}
}
/**
* Parameterization class.
*
* @author Erich Schubert
*
* @apiviz.exclude
*/
public static class Parameterizer extends AbstractParameterizer {
/**
* Flag to specify the "curves" rendering style.
*
*
* Key: {@code -histogram.curves}
*
*/
public static final OptionID STYLE_CURVES_ID = new OptionID("projhistogram.curves", "Use curves instead of the stacked histogram style.");
/**
* Parameter to specify the number of bins to use in histogram.
*
*
* Key: {@code -projhistogram.bins} Default: 80
*
*/
public static final OptionID HISTOGRAM_BINS_ID = new OptionID("projhistogram.bins", "Number of bins in the distribution histogram");
/**
* Internal storage of the curves flag.
*/
protected boolean curves = false;
/**
* Number of bins to use in the histogram.
*/
protected int bins = DEFAULT_BINS;
@Override
protected void makeOptions(Parameterization config) {
super.makeOptions(config);
Flag curvesF = new Flag(STYLE_CURVES_ID);
if(config.grab(curvesF)) {
curves = curvesF.isTrue();
}
IntParameter binsP = new IntParameter(HISTOGRAM_BINS_ID, DEFAULT_BINS);
binsP.addConstraint(CommonConstraints.GREATER_THAN_ONE_INT);
if(config.grab(binsP)) {
bins = binsP.intValue();
}
}
@Override
protected ColoredHistogramVisualizer makeInstance() {
return new ColoredHistogramVisualizer(this);
}
}
}
package-info.java 0000775 0000000 0000000 00000001756 12657057427 0037575 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/histogram /**
*
Visualizers based on 1D projected histograms.
*
*/
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.lmu.ifi.dbs.elki.visualization.visualizers.histogram; 0000775 0000000 0000000 00000000000 12657057427 0033676 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/optics AbstractOPTICSVisualization.java 0000664 0000000 0000000 00000006115 12657057427 0042013 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/optics package de.lmu.ifi.dbs.elki.visualization.visualizers.optics;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.apache.batik.util.SVGConstants;
import de.lmu.ifi.dbs.elki.algorithm.clustering.optics.ClusterOrder;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.gui.VisualizationPlot;
import de.lmu.ifi.dbs.elki.visualization.projections.OPTICSProjection;
import de.lmu.ifi.dbs.elki.visualization.projections.Projection;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
import de.lmu.ifi.dbs.elki.visualization.visualizers.AbstractVisualization;
/**
* Abstract base class for OPTICS visualizer
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.uses OPTICSProjection
*/
public abstract class AbstractOPTICSVisualization extends AbstractVisualization {
/**
* The plot
*/
final protected OPTICSProjection optics;
/**
* Width of plot (in display units)
*/
protected double plotwidth;
/**
* Height of plot (in display units)
*/
protected double plotheight;
/**
* Constructor.
*
* @param task Visualization task.
* @param plot Plot to draw to
* @param width Embedding width
* @param height Embedding height
* @param proj Projection
*/
public AbstractOPTICSVisualization(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj) {
super(task, plot, width, height);
this.optics = (OPTICSProjection) proj;
}
/**
* Produce a new layer element.
*/
protected void makeLayerElement() {
plotwidth = StyleLibrary.SCALE;
plotheight = StyleLibrary.SCALE / optics.getOPTICSPlot(context).getRatio();
final double margin = context.getStyleLibrary().getSize(StyleLibrary.MARGIN);
layer = SVGUtil.svgElement(svgp.getDocument(), SVGConstants.SVG_G_TAG);
final String transform = SVGUtil.makeMarginTransform(getWidth(), getHeight(), plotwidth, plotheight, margin * .5, margin * .5, margin * 1.5, margin * .5);
SVGUtil.setAtt(layer, SVGConstants.SVG_TRANSFORM_ATTRIBUTE, transform);
}
/**
* Access the raw cluster order
*
* @return Cluster order
*/
protected ClusterOrder getClusterOrder() {
return optics.getResult();
}
} OPTICSClusterVisualization.java 0000664 0000000 0000000 00000020024 12657057427 0041664 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/optics package de.lmu.ifi.dbs.elki.visualization.visualizers.optics;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.HashMap;
import java.util.Map;
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
import de.lmu.ifi.dbs.elki.data.Cluster;
import de.lmu.ifi.dbs.elki.data.Clustering;
import de.lmu.ifi.dbs.elki.data.model.OPTICSModel;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.result.Result;
import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.Hierarchy;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTree;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.colors.ColorLibrary;
import de.lmu.ifi.dbs.elki.visualization.css.CSSClass;
import de.lmu.ifi.dbs.elki.visualization.gui.VisualizationPlot;
import de.lmu.ifi.dbs.elki.visualization.projections.Projection;
import de.lmu.ifi.dbs.elki.visualization.projector.OPTICSProjector;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
import de.lmu.ifi.dbs.elki.visualization.visualizers.AbstractVisFactory;
import de.lmu.ifi.dbs.elki.visualization.visualizers.Visualization;
/**
* Visualize the clusters and cluster hierarchy found by OPTICS on the OPTICS
* Plot.
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.stereotype factory
* @apiviz.uses Instance oneway - - «create»
*/
public class OPTICSClusterVisualization extends AbstractVisFactory {
/**
* The logger for this class.
*/
private static final Logging LOG = Logging.getLogger(OPTICSClusterVisualization.class);
/**
* A short name characterizing this Visualizer.
*/
private static final String NAME = "OPTICS Cluster Ranges";
/**
* Constructor.
*/
public OPTICSClusterVisualization() {
super();
}
@Override
public void processNewResult(VisualizerContext context, Object result) {
Hierarchy.Iter it = VisualizationTree.filter(context, result, OPTICSProjector.class);
for(; it.valid(); it.advance()) {
OPTICSProjector p = it.get();
final Clustering ocl = findOPTICSClustering(context, p.getResult());
if(ocl != null) {
final VisualizationTask task = new VisualizationTask(NAME, context, ocl, null, this);
task.level = VisualizationTask.LEVEL_DATA;
context.addVis(p, task);
// TODO: use and react to style policy!
}
}
// TODO: also run when a new clustering is added, instead of just new
// projections?
}
@Override
public Visualization makeVisualization(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj) {
return new Instance(task, plot, width, height, proj);
}
@Override
public boolean allowThumbnails(VisualizationTask task) {
// Don't use thumbnails
return false;
}
/**
* Find the first OPTICS clustering child of a result.
*
* @param context Result context
* @param start Result to start searching at
* @return OPTICS clustering
*/
@SuppressWarnings("unchecked")
protected static Clustering findOPTICSClustering(VisualizerContext context, Result start) {
Hierarchy.Iter> it1 = VisualizationTree.filterResults(context, start, Clustering.class);
for(; it1.valid(); it1.advance()) {
Clustering> clus = it1.get();
if(clus.getToplevelClusters().size() == 0) {
continue;
}
try {
Cluster> firstcluster = clus.getToplevelClusters().iterator().next();
if(firstcluster.getModel() instanceof OPTICSModel) {
return (Clustering) clus;
}
}
catch(Exception e) {
// Empty clustering? Shouldn't happen.
LOG.warning("Clustering with no cluster detected.", e);
}
}
return null;
}
/**
* Instance.
*
* @author Erich Schubert
*
* @apiviz.uses Clustering oneway - - «visualizes»
*/
public class Instance extends AbstractOPTICSVisualization {
/**
* CSS class for markers
*/
protected static final String CSS_BRACKET = "opticsBracket";
/**
* Our clustering
*/
Clustering clus;
/**
* Constructor.
*
* @param task Visualization task
* @param plot Plot to draw to
* @param width Embedding width
* @param height Embedding height
* @param proj Projection
*/
public Instance(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj) {
super(task, plot, width, height, proj);
this.clus = task.getResult();
addListeners();
}
@Override
public void fullRedraw() {
makeLayerElement();
addCSSClasses();
ColorLibrary colors = context.getStyleLibrary().getColorSet(StyleLibrary.PLOT);
HashMap, String> colormap = new HashMap<>();
int cnum = 0;
for(Cluster> c : clus.getAllClusters()) {
colormap.put(c, colors.getColor(cnum));
cnum++;
}
drawClusters(clus, clus.iterToplevelClusters(), 1, colormap);
}
/**
* Recursively draw clusters
*
* @param clusters Current set of clusters
* @param depth Recursion depth
* @param colormap Color mapping
*/
private void drawClusters(Clustering clustering, Hierarchy.Iter> clusters, int depth, Map, String> colormap) {
final double scale = StyleLibrary.SCALE;
for(; clusters.valid(); clusters.advance()) {
Cluster cluster = clusters.get();
try {
OPTICSModel model = cluster.getModel();
final double x1 = plotwidth * ((model.getStartIndex() + .25) / this.optics.getResult().size());
final double x2 = plotwidth * ((model.getEndIndex() + .75) / this.optics.getResult().size());
final double y = plotheight + depth * scale * 0.01;
Element e = svgp.svgLine(x1, y, x2, y);
SVGUtil.addCSSClass(e, CSS_BRACKET);
String color = colormap.get(cluster);
if(color != null) {
SVGUtil.setAtt(e, SVGConstants.SVG_STYLE_ATTRIBUTE, SVGConstants.CSS_STROKE_PROPERTY + ":" + color);
}
layer.appendChild(e);
}
catch(ClassCastException e) {
LOG.warning("Expected OPTICSModel, got: " + cluster.getModel().getClass().getSimpleName());
}
// Descend
final Hierarchy.Iter> children = clustering.getClusterHierarchy().iterChildren(cluster);
if(children != null) {
drawClusters(clustering, children, depth + 1, colormap);
}
}
}
/**
* Adds the required CSS-Classes
*/
private void addCSSClasses() {
// Class for the markers
if(!svgp.getCSSClassManager().contains(CSS_BRACKET)) {
final CSSClass cls = new CSSClass(this, CSS_BRACKET);
final StyleLibrary style = context.getStyleLibrary();
cls.setStatement(SVGConstants.CSS_STROKE_PROPERTY, style.getColor(StyleLibrary.PLOT));
cls.setStatement(SVGConstants.CSS_STROKE_WIDTH_PROPERTY, style.getLineWidth(StyleLibrary.PLOT));
svgp.addCSSClassOrLogError(cls);
}
}
}
}
OPTICSPlotCutVisualization.java 0000664 0000000 0000000 00000023147 12657057427 0041646 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/optics package de.lmu.ifi.dbs.elki.visualization.visualizers.optics;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.apache.batik.util.SVG12Constants;
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
import org.w3c.dom.events.Event;
import org.w3c.dom.svg.SVGPoint;
import de.lmu.ifi.dbs.elki.algorithm.clustering.optics.ClusterOrder;
import de.lmu.ifi.dbs.elki.data.Clustering;
import de.lmu.ifi.dbs.elki.data.model.Model;
import de.lmu.ifi.dbs.elki.utilities.FormatUtil;
import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.Hierarchy;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTree;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.batikutil.DragableArea;
import de.lmu.ifi.dbs.elki.visualization.css.CSSClass;
import de.lmu.ifi.dbs.elki.visualization.gui.VisualizationPlot;
import de.lmu.ifi.dbs.elki.visualization.opticsplot.OPTICSCut;
import de.lmu.ifi.dbs.elki.visualization.opticsplot.OPTICSPlot;
import de.lmu.ifi.dbs.elki.visualization.projections.Projection;
import de.lmu.ifi.dbs.elki.visualization.projector.OPTICSProjector;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
import de.lmu.ifi.dbs.elki.visualization.visualizers.AbstractVisFactory;
import de.lmu.ifi.dbs.elki.visualization.visualizers.Visualization;
/**
* Visualizes a cut in an OPTICS Plot to select an Epsilon value and generate a
* new clustering result.
*
* @author Heidi Kolb
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.stereotype factory
* @apiviz.uses Instance oneway - - «create»
*/
public class OPTICSPlotCutVisualization extends AbstractVisFactory {
/**
* A short name characterizing this Visualizer.
*/
private static final String NAME = "OPTICS Cut";
/**
* Constructor.
*/
public OPTICSPlotCutVisualization() {
super();
}
@Override
public void processNewResult(VisualizerContext context, Object result) {
Hierarchy.Iter it = VisualizationTree.filter(context, result, OPTICSProjector.class);
for(; it.valid(); it.advance()) {
OPTICSProjector p = it.get();
final VisualizationTask task = new VisualizationTask(NAME, context, p.getResult(), null, this);
task.level = VisualizationTask.LEVEL_INTERACTIVE;
context.addVis(p, task);
}
}
@Override
public Visualization makeVisualization(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj) {
return new Instance(task, plot, width, height, proj);
}
@Override
public boolean allowThumbnails(VisualizationTask task) {
// Don't use thumbnails
return false;
}
/**
* Instance.
*
* @author Heidi Kolb
* @author Erich Schubert
*/
public class Instance extends AbstractOPTICSVisualization implements DragableArea.DragListener {
/**
* CSS-Styles
*/
protected static final String CSS_LINE = "opticsPlotLine";
/**
* CSS-Styles
*/
protected static final String CSS_EPSILON = "opticsPlotEpsilonValue";
/**
* The current epsilon value.
*/
private double epsilon = 0.0;
/**
* Sensitive (clickable) area
*/
private DragableArea eventarea = null;
/**
* The label element
*/
private Element elemText = null;
/**
* The line element
*/
private Element elementLine = null;
/**
* The drag handle element
*/
private Element elementPoint = null;
/**
* Constructor.
*
* @param task Task
* @param plot Plot to draw to
* @param width Embedding width
* @param height Embedding height
* @param proj Projection
*/
public Instance(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj) {
super(task, plot, width, height, proj);
}
@Override
public void fullRedraw() {
incrementalRedraw();
}
@Override
public void incrementalRedraw() {
if(layer == null) {
makeLayerElement();
addCSSClasses();
}
// TODO make the number of digits configurable
final String label = (epsilon > 0.0) ? FormatUtil.NF4.format(epsilon) : "";
// compute absolute y-value of bar
final double yAct = getYFromEpsilon(epsilon);
if(elemText == null) {
elemText = svgp.svgText(StyleLibrary.SCALE * 1.05, yAct, label);
SVGUtil.setAtt(elemText, SVGConstants.SVG_CLASS_ATTRIBUTE, CSS_EPSILON);
layer.appendChild(elemText);
}
else {
elemText.setTextContent(label);
SVGUtil.setAtt(elemText, SVGConstants.SVG_Y_ATTRIBUTE, yAct);
}
// line and handle
if(elementLine == null) {
elementLine = svgp.svgLine(0, yAct, StyleLibrary.SCALE * 1.04, yAct);
SVGUtil.addCSSClass(elementLine, CSS_LINE);
layer.appendChild(elementLine);
}
else {
SVGUtil.setAtt(elementLine, SVG12Constants.SVG_Y1_ATTRIBUTE, yAct);
SVGUtil.setAtt(elementLine, SVG12Constants.SVG_Y2_ATTRIBUTE, yAct);
}
if(elementPoint == null) {
elementPoint = svgp.svgCircle(StyleLibrary.SCALE * 1.04, yAct, StyleLibrary.SCALE * 0.004);
SVGUtil.addCSSClass(elementPoint, CSS_LINE);
layer.appendChild(elementPoint);
}
else {
SVGUtil.setAtt(elementPoint, SVG12Constants.SVG_CY_ATTRIBUTE, yAct);
}
if(eventarea == null) {
eventarea = new DragableArea(svgp, StyleLibrary.SCALE, -StyleLibrary.SCALE * 0.01, //
StyleLibrary.SCALE * 0.1, plotheight + StyleLibrary.SCALE * 0.02, this);
layer.appendChild(eventarea.getElement());
}
}
@Override
public void destroy() {
super.destroy();
eventarea.destroy();
}
/**
* Get epsilon from y-value
*
* @param y y-Value
* @return epsilon
*/
protected double getEpsilonFromY(double y) {
OPTICSPlot opticsplot = optics.getOPTICSPlot(context);
y = (y < 0) ? 0 : (y > plotheight) ? 1. : y / plotheight;
return optics.getOPTICSPlot(context).scaleFromPixel(y * opticsplot.getHeight());
}
/**
* Get y-value from epsilon
*
* @param epsilon epsilon
* @return y-Value
*/
protected double getYFromEpsilon(double epsilon) {
OPTICSPlot opticsplot = optics.getOPTICSPlot(context);
int h = opticsplot.getHeight();
double y = opticsplot.getScale().getScaled(epsilon, h - .5, .5) / (double) h * plotheight;
return (y < 0.) ? 0. : (y > plotheight) ? plotheight : y;
}
@Override
public boolean startDrag(SVGPoint start, Event evt) {
epsilon = getEpsilonFromY(plotheight - start.getY());
// opvis.unsetEpsilonExcept(this);
svgp.requestRedraw(this.task, this);
return true;
}
@Override
public boolean duringDrag(SVGPoint start, SVGPoint end, Event evt, boolean inside) {
if(inside) {
epsilon = getEpsilonFromY(plotheight - end.getY());
}
// opvis.unsetEpsilonExcept(this);
svgp.requestRedraw(this.task, this);
return true;
}
@Override
public boolean endDrag(SVGPoint start, SVGPoint end, Event evt, boolean inside) {
if(inside) {
epsilon = getEpsilonFromY(plotheight - end.getY());
// opvis.unsetEpsilonExcept(this);
// FIXME: replace an existing optics cut result!
final ClusterOrder order = optics.getResult();
Clustering cl = OPTICSCut.makeOPTICSCut(order, epsilon);
order.addChildResult(cl);
}
svgp.requestRedraw(this.task, this);
return true;
}
/**
* Reset the epsilon value.
*/
public void unsetEpsilon() {
epsilon = 0.0;
}
/**
* Adds the required CSS-Classes
*/
private void addCSSClasses() {
// Class for the epsilon-value
final StyleLibrary style = context.getStyleLibrary();
if(!svgp.getCSSClassManager().contains(CSS_EPSILON)) {
final CSSClass label = new CSSClass(svgp, CSS_EPSILON);
label.setStatement(SVGConstants.CSS_FILL_PROPERTY, style.getTextColor(StyleLibrary.AXIS_LABEL));
label.setStatement(SVGConstants.CSS_FONT_FAMILY_PROPERTY, style.getFontFamily(StyleLibrary.AXIS_LABEL));
label.setStatement(SVGConstants.CSS_FONT_SIZE_PROPERTY, style.getTextSize(StyleLibrary.AXIS_LABEL));
svgp.addCSSClassOrLogError(label);
}
// Class for the epsilon cut line
if(!svgp.getCSSClassManager().contains(CSS_LINE)) {
final CSSClass lcls = new CSSClass(svgp, CSS_LINE);
lcls.setStatement(SVGConstants.CSS_STROKE_PROPERTY, style.getColor(StyleLibrary.PLOT));
lcls.setStatement(SVGConstants.CSS_STROKE_WIDTH_PROPERTY, 0.5 * style.getLineWidth(StyleLibrary.PLOT));
svgp.addCSSClassOrLogError(lcls);
}
}
}
}
OPTICSPlotSelectionVisualization.java 0000664 0000000 0000000 00000027265 12657057427 0043045 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/optics package de.lmu.ifi.dbs.elki.visualization.visualizers.optics;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.apache.batik.dom.events.DOMMouseEvent;
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
import org.w3c.dom.events.Event;
import org.w3c.dom.svg.SVGPoint;
import de.lmu.ifi.dbs.elki.algorithm.clustering.optics.ClusterOrder;
import de.lmu.ifi.dbs.elki.database.ids.DBIDArrayIter;
import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil;
import de.lmu.ifi.dbs.elki.database.ids.DBIDs;
import de.lmu.ifi.dbs.elki.database.ids.HashSetModifiableDBIDs;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.result.DBIDSelection;
import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.Hierarchy;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTree;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.batikutil.DragableArea;
import de.lmu.ifi.dbs.elki.visualization.css.CSSClass;
import de.lmu.ifi.dbs.elki.visualization.gui.VisualizationPlot;
import de.lmu.ifi.dbs.elki.visualization.projections.Projection;
import de.lmu.ifi.dbs.elki.visualization.projector.OPTICSProjector;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
import de.lmu.ifi.dbs.elki.visualization.visualizers.AbstractVisFactory;
import de.lmu.ifi.dbs.elki.visualization.visualizers.Visualization;
/**
* Handle the marker in an OPTICS plot.
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.stereotype factory
* @apiviz.uses Instance oneway - - «create»
*/
public class OPTICSPlotSelectionVisualization extends AbstractVisFactory {
/**
* The logger for this class.
*/
private static final Logging LOG = Logging.getLogger(OPTICSPlotSelectionVisualization.class);
/**
* A short name characterizing this Visualizer.
*/
private static final String NAME = "OPTICS Selection";
/**
* Input modes
*
* @apiviz.exclude
*/
// TODO: Refactor all Mode copies into a shared class?
private enum Mode {
REPLACE, ADD, INVERT
}
/**
* Constructor.
*/
public OPTICSPlotSelectionVisualization() {
super();
}
@Override
public void processNewResult(VisualizerContext context, Object result) {
Hierarchy.Iter it = VisualizationTree.filter(context, result, OPTICSProjector.class);
for(; it.valid(); it.advance()) {
OPTICSProjector p = it.get();
final VisualizationTask task = new VisualizationTask(NAME, context, p.getResult(), null, this);
task.level = VisualizationTask.LEVEL_INTERACTIVE;
task.addUpdateFlags(VisualizationTask.ON_SELECTION);
context.addVis(p, task);
}
}
@Override
public Visualization makeVisualization(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj) {
return new Instance(task, plot, width, height, proj);
}
@Override
public boolean allowThumbnails(VisualizationTask task) {
// Don't use thumbnails
return false;
}
/**
* Instance.
*
* @author Heidi Kolb
* @author Erich Schubert
*
* @apiviz.uses DBIDSelection oneway - 1 visualizes
*/
public class Instance extends AbstractOPTICSVisualization implements DragableArea.DragListener {
/**
* CSS class for markers
*/
protected static final String CSS_MARKER = "opticsPlotMarker";
/**
* CSS class for markers
*/
protected static final String CSS_RANGEMARKER = "opticsPlotRangeMarker";
/**
* Element for the events
*/
private Element etag;
/**
* Element for the marker
*/
private Element mtag;
/**
* Constructor.
*
* @param task Visualization task
* @param plot Plot to draw to
* @param width Embedding width
* @param height Embedding height
* @param proj Projection
*/
public Instance(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj) {
super(task, plot, width, height, proj);
addListeners();
}
@Override
public void fullRedraw() {
makeLayerElement();
addCSSClasses();
mtag = svgp.svgElement(SVGConstants.SVG_G_TAG);
addMarker();
DragableArea drag = new DragableArea(svgp, 0 - plotwidth * 0.1, 0, plotwidth * 1.1, plotheight, this);
etag = drag.getElement();
// mtag first, etag must be the top Element
layer.appendChild(mtag);
layer.appendChild(etag);
}
/**
* Add marker for the selected IDs to mtag
*/
public void addMarker() {
ClusterOrder order = getClusterOrder();
// TODO: replace mtag!
DBIDSelection selContext = context.getSelection();
if(selContext != null) {
DBIDs selection = DBIDUtil.ensureSet(selContext.getSelectedIds());
final double width = plotwidth / order.size();
int begin = -1, j = 0;
for(DBIDIter it = order.iter(); it.valid(); it.advance(), j++) {
if(selection.contains(it)) {
if(begin == -1) {
begin = j;
}
}
else {
if(begin != -1) {
Element marker = addMarkerRect(begin * width, (j - begin) * width);
SVGUtil.addCSSClass(marker, CSS_MARKER);
mtag.appendChild(marker);
begin = -1;
}
}
}
// tail
if(begin != -1) {
Element marker = addMarkerRect(begin * width, (order.size() - begin) * width);
SVGUtil.addCSSClass(marker, CSS_MARKER);
mtag.appendChild(marker);
}
}
}
/**
* Create a rectangle as marker (Marker higher than plot!)
*
* @param x1 X-Value for the marker
* @param width Width of an entry
* @return SVG-Element svg-rectangle
*/
public Element addMarkerRect(double x1, double width) {
return svgp.svgRect(x1, 0, width, plotheight);
}
@Override
public boolean startDrag(SVGPoint startPoint, Event evt) {
ClusterOrder order = getClusterOrder();
int mouseActIndex = getSelectedIndex(order, startPoint);
if(mouseActIndex >= 0 && mouseActIndex < order.size()) {
double width = plotwidth / order.size();
double x1 = mouseActIndex * width;
Element marker = addMarkerRect(x1, width);
SVGUtil.setCSSClass(marker, CSS_RANGEMARKER);
mtag.appendChild(marker);
return true;
}
return false;
}
@Override
public boolean duringDrag(SVGPoint startPoint, SVGPoint dragPoint, Event evt, boolean inside) {
ClusterOrder order = getClusterOrder();
int mouseDownIndex = getSelectedIndex(order, startPoint);
int mouseActIndex = getSelectedIndex(order, dragPoint);
final int begin = Math.max(Math.min(mouseDownIndex, mouseActIndex), 0);
final int end = Math.min(Math.max(mouseDownIndex, mouseActIndex), order.size());
double width = plotwidth / order.size();
double x1 = begin * width;
double x2 = (end * width) + width;
mtag.removeChild(mtag.getLastChild());
Element marker = addMarkerRect(x1, x2 - x1);
SVGUtil.setCSSClass(marker, CSS_RANGEMARKER);
mtag.appendChild(marker);
return true;
}
@Override
public boolean endDrag(SVGPoint startPoint, SVGPoint dragPoint, Event evt, boolean inside) {
ClusterOrder order = getClusterOrder();
int mouseDownIndex = getSelectedIndex(order, startPoint);
int mouseActIndex = getSelectedIndex(order, dragPoint);
Mode mode = getInputMode(evt);
final int begin = Math.max(Math.min(mouseDownIndex, mouseActIndex), 0);
final int end = Math.min(Math.max(mouseDownIndex, mouseActIndex), order.size());
updateSelection(mode, begin, end);
return true;
}
/**
* Get the current input mode, on each mouse event.
*
* @param evt Mouse event.
* @return Input mode
*/
private Mode getInputMode(Event evt) {
if(evt instanceof DOMMouseEvent) {
DOMMouseEvent domme = (DOMMouseEvent) evt;
// TODO: visual indication of mode possible?
if(domme.getShiftKey()) {
return Mode.ADD;
}
else if(domme.getCtrlKey()) {
return Mode.INVERT;
}
else {
return Mode.REPLACE;
}
}
// Default mode is replace.
return Mode.REPLACE;
}
/**
* Gets the Index of the ClusterOrderEntry where the event occurred
*
* @param order List of ClusterOrderEntries
* @param cPt clicked point
* @return Index of the object
*/
private int getSelectedIndex(ClusterOrder order, SVGPoint cPt) {
int mouseActIndex = (int) ((cPt.getX() / plotwidth) * order.size());
return mouseActIndex;
}
/**
* Updates the selection for the given ClusterOrderEntry.
*
* @param mode Input mode
* @param begin first index to select
* @param end last index to select
*/
protected void updateSelection(Mode mode, int begin, int end) {
ClusterOrder order = getClusterOrder();
if(begin < 0 || begin > end || end >= order.size()) {
LOG.warning("Invalid range in updateSelection: " + begin + " .. " + end);
return;
}
DBIDSelection selContext = context.getSelection();
HashSetModifiableDBIDs selection;
if(selContext == null || mode == Mode.REPLACE) {
selection = DBIDUtil.newHashSet();
}
else {
selection = DBIDUtil.newHashSet(selContext.getSelectedIds());
}
for(DBIDArrayIter it = order.iter().seek(begin); it.getOffset() <= end; it.advance()) {
if(mode == Mode.INVERT) {
if(!selection.contains(it)) {
selection.add(it);
}
else {
selection.remove(it);
}
}
else {
// In REPLACE and ADD, add objects.
// The difference was done before by not re-using the selection.
// Since we are using a set, we can just add in any case.
selection.add(it);
}
}
context.setSelection(new DBIDSelection(selection));
}
/**
* Adds the required CSS-Classes
*/
private void addCSSClasses() {
// Class for the markers
if(!svgp.getCSSClassManager().contains(CSS_MARKER)) {
final CSSClass cls = new CSSClass(this, CSS_MARKER);
cls.setStatement(SVGConstants.CSS_FILL_PROPERTY, SVGConstants.CSS_BLUE_VALUE);
cls.setStatement(SVGConstants.CSS_OPACITY_PROPERTY, "0.2");
svgp.addCSSClassOrLogError(cls);
}
// Class for the range marking
if(!svgp.getCSSClassManager().contains(CSS_RANGEMARKER)) {
final CSSClass rcls = new CSSClass(this, CSS_RANGEMARKER);
rcls.setStatement(SVGConstants.CSS_FILL_PROPERTY, SVGConstants.CSS_RED_VALUE);
rcls.setStatement(SVGConstants.CSS_OPACITY_PROPERTY, "0.2");
svgp.addCSSClassOrLogError(rcls);
}
}
}
} OPTICSPlotVisualizer.java 0000664 0000000 0000000 00000012640 12657057427 0040462 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/optics package de.lmu.ifi.dbs.elki.visualization.visualizers.optics;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
import de.lmu.ifi.dbs.elki.logging.LoggingUtil;
import de.lmu.ifi.dbs.elki.math.scales.LinearScale;
import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.Hierarchy;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTree;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.css.CSSClassManager.CSSNamingConflict;
import de.lmu.ifi.dbs.elki.visualization.gui.VisualizationPlot;
import de.lmu.ifi.dbs.elki.visualization.opticsplot.OPTICSPlot;
import de.lmu.ifi.dbs.elki.visualization.projections.Projection;
import de.lmu.ifi.dbs.elki.visualization.projector.OPTICSProjector;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGSimpleLinearAxis;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
import de.lmu.ifi.dbs.elki.visualization.visualizers.AbstractVisFactory;
import de.lmu.ifi.dbs.elki.visualization.visualizers.Visualization;
/**
* Visualize an OPTICS result by constructing an OPTICS plot for it.
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.stereotype factory
* @apiviz.uses Instance oneway - - «create»
*/
public class OPTICSPlotVisualizer extends AbstractVisFactory {
/**
* Name for this visualizer.
*/
private static final String NAME = "OPTICS Plot";
/**
* Constructor.
*/
public OPTICSPlotVisualizer() {
super();
}
@Override
public void processNewResult(VisualizerContext context, Object result) {
Hierarchy.Iter it = VisualizationTree.filter(context, result, OPTICSProjector.class);
for(; it.valid(); it.advance()) {
OPTICSProjector p = it.get();
// Add plots, attach visualizer
final VisualizationTask task = new VisualizationTask(NAME, context, p.getResult(), null, this);
task.level = VisualizationTask.LEVEL_DATA;
// FIXME: task.setUpdates(VisualizationTask.ON_STYLEPOLICY);
context.addVis(p, task);
}
}
@Override
public Visualization makeVisualization(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj) {
return new Instance(task, plot, width, height, proj);
}
@Override
public boolean allowThumbnails(VisualizationTask task) {
// Don't use thumbnails
return false;
}
/**
* Instance.
*
* @author Erich Schubert
*/
public class Instance extends AbstractOPTICSVisualization {
/**
* Constructor.
*
* @param task Visualization task
* @param plot Plot to draw to
* @param width Embedding width
* @param height Embedding height
* @param proj Projection
*/
public Instance(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj) {
super(task, plot, width, height, proj);
addListeners();
}
@Override
public void fullRedraw() {
makeLayerElement();
// addCSSClasses();
OPTICSPlot opticsplot = optics.getOPTICSPlot(context);
String ploturi = opticsplot.getSVGPlotURI();
Element itag = svgp.svgElement(SVGConstants.SVG_IMAGE_TAG);
SVGUtil.setAtt(itag, SVGConstants.SVG_PRESERVE_ASPECT_RATIO_ATTRIBUTE, SVGConstants.SVG_NONE_VALUE);
SVGUtil.setAtt(itag, SVGConstants.SVG_IMAGE_RENDERING_ATTRIBUTE, SVGConstants.SVG_OPTIMIZE_SPEED_VALUE);
SVGUtil.setAtt(itag, SVGConstants.SVG_X_ATTRIBUTE, 0);
SVGUtil.setAtt(itag, SVGConstants.SVG_Y_ATTRIBUTE, 0);
SVGUtil.setAtt(itag, SVGConstants.SVG_WIDTH_ATTRIBUTE, plotwidth);
SVGUtil.setAtt(itag, SVGConstants.SVG_HEIGHT_ATTRIBUTE, plotheight);
itag.setAttributeNS(SVGConstants.XLINK_NAMESPACE_URI, SVGConstants.XLINK_HREF_QNAME, ploturi);
layer.appendChild(itag);
LinearScale scale = opticsplot.getScale();
double y1 = plotheight * opticsplot.scaleToPixel(scale.getMin()) / opticsplot.getHeight();
double y2 = plotheight * opticsplot.scaleToPixel(scale.getMax()) / opticsplot.getHeight();
try {
final StyleLibrary style = context.getStyleLibrary();
SVGSimpleLinearAxis.drawAxis(svgp, layer, scale, 0, y1, 0, y2, SVGSimpleLinearAxis.LabelStyle.LEFTHAND, style);
SVGSimpleLinearAxis.drawAxis(svgp, layer, scale, plotwidth, y1, plotwidth, y2, SVGSimpleLinearAxis.LabelStyle.RIGHTHAND, style);
}
catch(CSSNamingConflict e) {
LoggingUtil.exception("CSS naming conflict for axes on OPTICS plot", e);
}
}
}
} OPTICSSteepAreaVisualization.java 0000664 0000000 0000000 00000016753 12657057427 0042132 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/optics package de.lmu.ifi.dbs.elki.visualization.visualizers.optics;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.awt.Color;
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
import de.lmu.ifi.dbs.elki.algorithm.clustering.optics.ClusterOrder;
import de.lmu.ifi.dbs.elki.algorithm.clustering.optics.OPTICSXi;
import de.lmu.ifi.dbs.elki.algorithm.clustering.optics.OPTICSXi.SteepAreaResult;
import de.lmu.ifi.dbs.elki.database.ids.DBIDArrayIter;
import de.lmu.ifi.dbs.elki.result.Result;
import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.Hierarchy;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTree;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.css.CSSClass;
import de.lmu.ifi.dbs.elki.visualization.gui.VisualizationPlot;
import de.lmu.ifi.dbs.elki.visualization.opticsplot.OPTICSPlot;
import de.lmu.ifi.dbs.elki.visualization.projections.Projection;
import de.lmu.ifi.dbs.elki.visualization.projector.OPTICSProjector;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
import de.lmu.ifi.dbs.elki.visualization.visualizers.AbstractVisFactory;
import de.lmu.ifi.dbs.elki.visualization.visualizers.Visualization;
/**
* Visualize the steep areas found in an OPTICS plot
*
* @author Erich Schubert
* @since 0.4.0
*
* @apiviz.stereotype factory
* @apiviz.uses Instance oneway - - «create»
*/
public class OPTICSSteepAreaVisualization extends AbstractVisFactory {
/**
* A short name characterizing this Visualizer.
*/
private static final String NAME = "OPTICS Steep Areas";
/**
* Constructor.
*/
public OPTICSSteepAreaVisualization() {
super();
}
@Override
public void processNewResult(VisualizerContext context, Object result) {
Hierarchy.Iter it = VisualizationTree.filter(context, result, OPTICSProjector.class);
for(; it.valid(); it.advance()) {
OPTICSProjector p = it.get();
final SteepAreaResult steep = findSteepAreaResult(p.getResult());
if(steep != null) {
final VisualizationTask task = new VisualizationTask(NAME, context, p.getResult(), null, this);
task.level = VisualizationTask.LEVEL_DATA + 1;
context.addVis(p, task);
context.addVis(steep, task);
}
}
}
@Override
public Visualization makeVisualization(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj) {
return new Instance(task, plot, width, height, proj);
}
@Override
public boolean allowThumbnails(VisualizationTask task) {
// Don't use thumbnails
return false;
}
/**
* Find the OPTICS clustering child of a cluster order.
*
* @param co Cluster order
* @return OPTICS clustering
*/
protected static OPTICSXi.SteepAreaResult findSteepAreaResult(ClusterOrder co) {
for(Hierarchy.Iter r = co.getHierarchy().iterChildren(co); r.valid(); r.advance()) {
if(OPTICSXi.SteepAreaResult.class.isInstance(r.get())) {
return (OPTICSXi.SteepAreaResult) r.get();
}
}
return null;
}
/**
* Instance
*
* @author Erich Schubert
*
* @apiviz.uses SteepAreaResult
*/
public class Instance extends AbstractOPTICSVisualization {
/**
* CSS class for markers
*/
protected static final String CSS_STEEP_UP = "opticsSteepUp";
/**
* CSS class for markers
*/
protected static final String CSS_STEEP_DOWN = "opticsSteepDown";
/**
* Our clustering
*/
OPTICSXi.SteepAreaResult areas;
/**
* Constructor.
*
* @param task Visualization task
* @param plot Plot to draw to
* @param width Embedding width
* @param height Embedding height
* @param proj Projection
*/
public Instance(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj) {
super(task, plot, width, height, proj);
this.areas = findSteepAreaResult(this.optics.getResult());
}
@Override
public void fullRedraw() {
makeLayerElement();
addCSSClasses();
final OPTICSPlot opticsplot = optics.getOPTICSPlot(context);
final ClusterOrder co = getClusterOrder();
final int oheight = opticsplot.getHeight();
final double xscale = plotwidth / (double) co.size();
final double yscale = plotheight / (double) oheight;
DBIDArrayIter tmp = co.iter();
for(OPTICSXi.SteepArea area : areas) {
final int st = area.getStartIndex();
final int en = area.getEndIndex();
// Note: make sure we are using doubles!
final double x1 = (st + .25);
final double x2 = (en + .75);
final double y1 = opticsplot.scaleToPixel(co.getReachability(tmp.seek(st)));
final double y2 = opticsplot.scaleToPixel(co.getReachability(tmp.seek(en)));
Element e = svgp.svgLine(x1 * xscale, y1 * yscale, x2 * xscale, y2 * yscale);
if(area instanceof OPTICSXi.SteepDownArea) {
SVGUtil.addCSSClass(e, CSS_STEEP_DOWN);
}
else {
SVGUtil.addCSSClass(e, CSS_STEEP_UP);
}
layer.appendChild(e);
}
}
/**
* Adds the required CSS-Classes
*/
private void addCSSClasses() {
// Class for the markers
final StyleLibrary style = context.getStyleLibrary();
if(!svgp.getCSSClassManager().contains(CSS_STEEP_DOWN)) {
final CSSClass cls = new CSSClass(this, CSS_STEEP_DOWN);
Color color = SVGUtil.stringToColor(style.getColor(StyleLibrary.PLOT));
if(color == null) {
color = Color.BLACK;
}
color = new Color((int) (color.getRed() * 0.6), (int) (color.getGreen() * 0.6 + 0.4 * 256.), (int) (color.getBlue() * 0.6));
cls.setStatement(SVGConstants.CSS_STROKE_PROPERTY, SVGUtil.colorToString(color));
cls.setStatement(SVGConstants.CSS_STROKE_WIDTH_PROPERTY, style.getLineWidth(StyleLibrary.PLOT) * .5);
svgp.addCSSClassOrLogError(cls);
}
if(!svgp.getCSSClassManager().contains(CSS_STEEP_UP)) {
final CSSClass cls = new CSSClass(this, CSS_STEEP_UP);
Color color = SVGUtil.stringToColor(style.getColor(StyleLibrary.PLOT));
if(color == null) {
color = Color.BLACK;
}
color = new Color((int) (color.getRed() * 0.6 + 0.4 * 256.), (int) (color.getGreen() * 0.6), (int) (color.getBlue() * 0.6));
cls.setStatement(SVGConstants.CSS_STROKE_PROPERTY, SVGUtil.colorToString(color));
cls.setStatement(SVGConstants.CSS_STROKE_WIDTH_PROPERTY, style.getLineWidth(StyleLibrary.PLOT) * .5);
svgp.addCSSClassOrLogError(cls);
}
}
}
}
package-info.java 0000775 0000000 0000000 00000001742 12657057427 0037074 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/optics /**
*
Visualizers that do work on OPTICS plots
*/
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.lmu.ifi.dbs.elki.visualization.visualizers.optics; package-info.java 0000775 0000000 0000000 00000002202 12657057427 0035563 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers /**
*
Visualizers for various results
*
* @apiviz.exclude de.lmu.ifi.dbs.elki.utilities.datastructures.AnyMap
* @apiviz.exclude Visualization.Factory
* @apiviz.exclude de.lmu.ifi.dbs.elki.visualization.gui.*
*/
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.lmu.ifi.dbs.elki.visualization.visualizers;
0000775 0000000 0000000 00000000000 12657057427 0035076 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/pairsegments CircleSegmentsVisualizer.java 0000664 0000000 0000000 00000063704 12657057427 0042740 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/pairsegments package de.lmu.ifi.dbs.elki.visualization.visualizers.pairsegments;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.awt.Color;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventListener;
import org.w3c.dom.events.EventTarget;
import org.w3c.dom.events.MouseEvent;
import de.lmu.ifi.dbs.elki.evaluation.clustering.pairsegments.Segment;
import de.lmu.ifi.dbs.elki.evaluation.clustering.pairsegments.Segments;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.math.MathUtil;
import de.lmu.ifi.dbs.elki.result.Result;
import de.lmu.ifi.dbs.elki.result.ResultListener;
import de.lmu.ifi.dbs.elki.utilities.FormatUtil;
import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.Hierarchy;
import de.lmu.ifi.dbs.elki.utilities.documentation.Reference;
import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTree;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.css.CSSClass;
import de.lmu.ifi.dbs.elki.visualization.gui.VisualizationPlot;
import de.lmu.ifi.dbs.elki.visualization.projections.Projection;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGCheckbox;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
import de.lmu.ifi.dbs.elki.visualization.visualizers.AbstractVisFactory;
import de.lmu.ifi.dbs.elki.visualization.visualizers.AbstractVisualization;
import de.lmu.ifi.dbs.elki.visualization.visualizers.Visualization;
/**
* Visualizer to draw circle segments of clusterings and enable interactive
* selection of segments. For "empty" segments, all related segments are
* selected instead, to visualize the differences.
*
*
* Reference:
* Evaluation of Clusterings – Metrics and Visual Support
* Elke Achtert, Sascha Goldhofer, Hans-Peter Kriegel, Erich Schubert, Arthur
* Zimek
* In: Proc. 28th International Conference on Data Engineering (ICDE) 2012
*
*
* @author Sascha Goldhofer
* @author Erich Schubert
* @since 0.5.0
*
* @apiviz.landmark
*
* @apiviz.stereotype factory
* @apiviz.uses Instance oneway - - «create»
*/
@Reference(title = "Evaluation of Clusterings – Metrics and Visual Support", //
authors = "Elke Achtert, Sascha Goldhofer, Hans-Peter Kriegel, Erich Schubert, Arthur Zimek", //
booktitle = "Proc. 28th International Conference on Data Engineering (ICDE) 2012", //
url = "http://dx.doi.org/10.1109/ICDE.2012.128")
public class CircleSegmentsVisualizer extends AbstractVisFactory {
/**
* Class logger
*/
private static final Logging LOG = Logging.getLogger(CircleSegmentsVisualizer.class);
/**
* CircleSegments visualizer name
*/
private static final String NAME = "CircleSegments";
/**
* Constructor
*/
public CircleSegmentsVisualizer() {
super();
}
@Override
public Visualization makeVisualization(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj) {
return new Instance(task, plot, width, height, proj);
}
@Override
public void processNewResult(VisualizerContext context, Object start) {
Hierarchy.Iter it1 = VisualizationTree.filterResults(context, start, Segments.class);
for(; it1.valid(); it1.advance()) {
Segments segmentResult = it1.get();
SegmentsStylingPolicy policy;
Hierarchy.Iter it = VisualizationTree.filter(context, segmentResult, SegmentsStylingPolicy.class);
if(it.valid()) {
policy = it.get();
}
else {
policy = new SegmentsStylingPolicy(segmentResult);
context.addVis(segmentResult, policy);
}
// create task for visualization
final VisualizationTask task = new VisualizationTask(NAME, context, policy, null, this);
task.reqwidth = 2.0;
task.reqheight = 2.0;
task.level = VisualizationTask.LEVEL_INTERACTIVE;
task.addUpdateFlags(VisualizationTask.ON_STYLEPOLICY);
context.addVis(segmentResult, task);
}
}
/**
* Instance
*
* @author Sascha Goldhofer
* @author Erich Schubert
*
* @apiviz.uses Segments
* @apiviz.has SegmentsStylingPolicy
*
*/
public class Instance extends AbstractVisualization implements ResultListener {
/** Minimum width (radian) of Segment */
private static final double SEGMENT_MIN_ANGLE = 0.01;
/** Gap (radian) between segments */
private static final double SEGMENT_MIN_SEP_ANGLE = 0.005;
/** Offset from center to first ring */
private static final double RADIUS_INNER = 0.04 * StyleLibrary.SCALE;
/** Margin between two rings */
private static final double RADIUS_DISTANCE = 0.01 * StyleLibrary.SCALE;
/** Radius of whole CircleSegments except selection border */
private static final double RADIUS_OUTER = 0.47 * StyleLibrary.SCALE;
/** Radius of highlight selection (outer ring) */
private static final double RADIUS_SELECTION = 0.02 * StyleLibrary.SCALE;
/**
* CSS class name for the clusterings.
*/
private static final String CLR_CLUSTER_CLASS_PREFIX = "clusterSegment";
/**
* CSS border class of a cluster
*/
public static final String CLR_BORDER_CLASS = "clusterBorder";
/**
* CSS hover class for clusters of hovered segment
*/
public static final String CLR_UNPAIRED_CLASS = "clusterUnpaired";
/**
* CSS hover class of a segment cluster
*/
public static final String CLR_HOVER_CLASS = "clusterHover";
/**
* CSS class of selected Segment
*/
public static final String SEG_UNPAIRED_SELECTED_CLASS = "unpairedSegmentSelected";
/**
* Style prefix
*/
public static final String STYLE = "segments";
/**
* Style for border lines
*/
public static final String STYLE_BORDER = STYLE + ".border";
/**
* Style for hover effect
*/
public static final String STYLE_HOVER = STYLE + ".hover";
/**
* First color for producing segment-cluster colors
*/
public static final String STYLE_GRADIENT_FIRST = STYLE + ".cluster.first";
/**
* Second color for producing segment-cluster colors
*/
public static final String STYLE_GRADIENT_SECOND = STYLE + ".cluster.second";
/**
* Segmentation of Clusterings
*/
protected final Segments segments;
/**
* The two main layers
*/
private Element visLayer, ctrlLayer;
/**
* Map to connect segments to their visual elements
*/
public Map> segmentToElements = new HashMap<>();
/**
* Show unclustered Pairs in CircleSegments
*/
boolean showUnclusteredPairs = false;
/**
* Styling policy
*/
protected final SegmentsStylingPolicy policy;
/**
* Flag to disallow an incremental redraw
*/
private boolean noIncrementalRedraw = true;
/**
* Constructor
*
* @param task Task
* @param plot Plot to draw to
* @param width Embedding width
* @param height Embedding height
* @param proj Projection
*/
public Instance(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj) {
super(task, plot, width, height);
policy = task.getResult();
segments = policy.segments;
// FIXME: handle this more generally.
policy.setStyleLibrary(context.getStyleLibrary());
addListeners();
}
public void toggleUnclusteredPairs(boolean show) {
noIncrementalRedraw = true;
showUnclusteredPairs = show;
svgp.requestRedraw(this.task, this);
}
@Override
public void resultChanged(Result current) {
super.resultChanged(current);
if(current == context.getStylingPolicy()) {
// When switching to a different policy, unhighlight segments.
if(context.getStylingPolicy() != policy) {
policy.deselectAllSegments();
}
}
}
@Override
public void incrementalRedraw() {
if(noIncrementalRedraw) {
super.incrementalRedraw();
}
else {
redrawSelection();
}
}
@Override
public void fullRedraw() {
LOG.debug("Full redraw");
noIncrementalRedraw = false; // Done that.
// initialize css (needs clusterSize!)
addCSSClasses(segments.getHighestClusterCount());
layer = svgp.svgElement(SVGConstants.SVG_G_TAG);
visLayer = svgp.svgElement(SVGConstants.SVG_G_TAG);
// Setup scaling for canvas: 0 to StyleLibrary.SCALE (usually 100 to avoid
// a
// Java drawing bug!)
String transform = SVGUtil.makeMarginTransform(task.reqwidth, task.reqheight, StyleLibrary.SCALE, StyleLibrary.SCALE, 0) + " translate(" + (StyleLibrary.SCALE * .5) + " " + (StyleLibrary.SCALE * .5) + ")";
visLayer.setAttribute(SVGConstants.SVG_TRANSFORM_ATTRIBUTE, transform);
ctrlLayer = svgp.svgElement(SVGConstants.SVG_G_TAG);
// and create svg elements
drawSegments();
//
// Build Interface
//
SVGCheckbox checkbox = new SVGCheckbox(showUnclusteredPairs, "Show unclustered pairs");
checkbox.addCheckBoxListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
toggleUnclusteredPairs(((SVGCheckbox) e.getSource()).isChecked());
}
});
// Add ring:clustering info
Element clrInfo = drawClusteringInfo();
Element c = checkbox.renderCheckBox(svgp, 1., 5. + FormatUtil.parseDouble(clrInfo.getAttribute(SVGConstants.SVG_HEIGHT_ATTRIBUTE)), 11);
ctrlLayer.appendChild(clrInfo);
ctrlLayer.appendChild(c);
ctrlLayer.setAttribute(SVGConstants.SVG_TRANSFORM_ATTRIBUTE, "scale(" + (0.25 / StyleLibrary.SCALE) + ")");
layer.appendChild(visLayer);
layer.appendChild(ctrlLayer);
}
/**
* Define and add required CSS classes
*/
protected void addCSSClasses(int maxClusterSize) {
StyleLibrary style = context.getStyleLibrary();
// Cluster separation lines
CSSClass cssReferenceBorder = new CSSClass(this.getClass(), CLR_BORDER_CLASS);
cssReferenceBorder.setStatement(SVGConstants.SVG_FILL_ATTRIBUTE, style.getColor(STYLE_BORDER));
svgp.addCSSClassOrLogError(cssReferenceBorder);
// Hover effect for clusters
CSSClass cluster_hover = new CSSClass(this.getClass(), CLR_HOVER_CLASS);
// Note: !important is needed to override the regular color assignment
cluster_hover.setStatement(SVGConstants.SVG_FILL_ATTRIBUTE, style.getColor(STYLE_HOVER) + " !important");
cluster_hover.setStatement(SVGConstants.SVG_CURSOR_TAG, SVGConstants.SVG_POINTER_VALUE);
svgp.addCSSClassOrLogError(cluster_hover);
// Unpaired cluster segment
CSSClass cluster_unpaired = new CSSClass(this.getClass(), CLR_UNPAIRED_CLASS);
cluster_unpaired.setStatement(SVGConstants.SVG_FILL_ATTRIBUTE, style.getBackgroundColor(STYLE));
cluster_unpaired.setStatement(SVGConstants.SVG_STROKE_ATTRIBUTE, SVGConstants.CSS_NONE_VALUE);
svgp.addCSSClassOrLogError(cluster_unpaired);
// Selected unpaired cluster segment
CSSClass cluster_unpaired_s = new CSSClass(this.getClass(), SEG_UNPAIRED_SELECTED_CLASS);
cluster_unpaired_s.setStatement(SVGConstants.SVG_FILL_ATTRIBUTE, style.getColor(STYLE_HOVER) + " !important");
svgp.addCSSClassOrLogError(cluster_unpaired_s);
// create Color shades for clusters
String firstcol = style.getColor(STYLE_GRADIENT_FIRST);
String secondcol = style.getColor(STYLE_GRADIENT_SECOND);
String[] clusterColorShades = makeGradient(maxClusterSize, new String[] { firstcol, secondcol });
for(int i = 0; i < maxClusterSize; i++) {
CSSClass clusterClasses = new CSSClass(CircleSegmentsVisualizer.class, CLR_CLUSTER_CLASS_PREFIX + "_" + i);
clusterClasses.setStatement(SVGConstants.SVG_FILL_ATTRIBUTE, clusterColorShades[i]);
clusterClasses.setStatement(SVGConstants.SVG_STROKE_ATTRIBUTE, SVGConstants.SVG_NONE_VALUE);
svgp.addCSSClassOrLogError(clusterClasses);
}
}
/**
* Create the segments
*/
private void drawSegments() {
final StyleLibrary style = context.getStyleLibrary();
final int clusterings = segments.getClusterings();
// Reinitialize
this.segmentToElements.clear();
double angle_pair = (MathUtil.TWOPI - (SEGMENT_MIN_SEP_ANGLE * segments.size())) / segments.getPairCount(showUnclusteredPairs);
final int pair_min_count = (int) Math.ceil(SEGMENT_MIN_ANGLE / angle_pair);
// number of segments needed to be resized
int cluster_min_count = 0;
for(Segment segment : segments) {
if(segment.getPairCount() <= pair_min_count) {
cluster_min_count++;
}
}
// update width of a pair
angle_pair = (MathUtil.TWOPI - (SEGMENT_MIN_SEP_ANGLE * segments.size() + cluster_min_count * SEGMENT_MIN_ANGLE)) / (segments.getPairCount(showUnclusteredPairs) - cluster_min_count);
double radius_delta = (RADIUS_OUTER - RADIUS_INNER - clusterings * RADIUS_DISTANCE) / clusterings;
double border_width = SEGMENT_MIN_SEP_ANGLE;
int refClustering = 0;
int refSegment = Segment.UNCLUSTERED;
double offsetAngle = 0.0;
for(final Segment segment : segments) {
long currentPairCount = segment.getPairCount();
// resize small segments if below minimum
double alpha = SEGMENT_MIN_ANGLE;
if(currentPairCount > pair_min_count) {
alpha = angle_pair * currentPairCount;
}
// ITERATE OVER ALL SEGMENT-CLUSTERS
ArrayList elems = new ArrayList<>(clusterings);
segmentToElements.put(segment, elems);
// draw segment for every clustering
for(int i = 0; i < clusterings; i++) {
double currentRadius = i * (radius_delta + RADIUS_DISTANCE) + RADIUS_INNER;
// Add border if the next segment is a different cluster in the
// reference clustering
if((refSegment != segment.get(refClustering)) && refClustering == i) {
Element border = SVGUtil.svgCircleSegment(svgp, 0, 0, offsetAngle - SEGMENT_MIN_SEP_ANGLE, border_width, currentRadius, RADIUS_OUTER - RADIUS_DISTANCE);
border.setAttribute(SVGConstants.SVG_CLASS_ATTRIBUTE, CLR_BORDER_CLASS);
visLayer.appendChild(border);
if(segment.get(refClustering) == Segment.UNCLUSTERED) {
refClustering = Math.min(refClustering + 1, clusterings - 1);
}
refSegment = segment.get(refClustering);
}
int cluster = segment.get(i);
// create ring segment
Element segelement = SVGUtil.svgCircleSegment(svgp, 0, 0, offsetAngle, alpha, currentRadius, currentRadius + radius_delta);
elems.add(segelement);
// MouseEvents on segment cluster
EventListener listener = new SegmentListenerProxy(segment, i);
EventTarget targ = (EventTarget) segelement;
targ.addEventListener(SVGConstants.SVG_MOUSEOVER_EVENT_TYPE, listener, false);
targ.addEventListener(SVGConstants.SVG_MOUSEOUT_EVENT_TYPE, listener, false);
targ.addEventListener(SVGConstants.SVG_CLICK_EVENT_TYPE, listener, false);
// Coloring based on clusterID
if(cluster >= 0) {
segelement.setAttribute(SVGConstants.SVG_CLASS_ATTRIBUTE, CLR_CLUSTER_CLASS_PREFIX + "_" + cluster);
}
// if its an unpaired cluster set color to white
else {
segelement.setAttribute(SVGConstants.SVG_CLASS_ATTRIBUTE, CLR_UNPAIRED_CLASS);
}
visLayer.appendChild(segelement);
}
//
// Add a extended strip for each segment to emphasis selection
// (easier to track thin segments and their color coding and
// differentiates them from cluster border lines)
//
double currentRadius = clusterings * (radius_delta + RADIUS_DISTANCE) + RADIUS_INNER;
Element extension = SVGUtil.svgCircleSegment(svgp, 0, 0, offsetAngle, alpha, currentRadius, currentRadius + RADIUS_SELECTION);
extension.setAttribute(SVGConstants.SVG_CLASS_ATTRIBUTE, CLR_UNPAIRED_CLASS);
elems.add(extension);
if(segment.isUnpaired()) {
if(policy.isSelected(segment)) {
SVGUtil.addCSSClass(extension, SEG_UNPAIRED_SELECTED_CLASS);
}
else {
// Remove highlight
SVGUtil.removeCSSClass(extension, SEG_UNPAIRED_SELECTED_CLASS);
}
}
else {
int idx = policy.indexOfSegment(segment);
if(idx >= 0) {
String color = style.getColorSet(StyleLibrary.PLOT).getColor(idx);
extension.setAttribute(SVGConstants.SVG_STYLE_ATTRIBUTE, SVGConstants.CSS_FILL_PROPERTY + ":" + color);
}
else {
// Remove styling
extension.removeAttribute(SVGConstants.SVG_STYLE_ATTRIBUTE);
}
}
visLayer.appendChild(extension);
// calculate angle for next segment
offsetAngle += alpha + SEGMENT_MIN_SEP_ANGLE;
}
}
private void redrawSelection() {
final StyleLibrary style = context.getStyleLibrary();
LOG.debug("Updating selection only.");
for(Entry> entry : segmentToElements.entrySet()) {
Segment segment = entry.getKey();
// The selection marker is the extra element in the list
Element extension = entry.getValue().get(segments.getClusterings());
if(segment.isUnpaired()) {
if(policy.isSelected(segment)) {
SVGUtil.addCSSClass(extension, SEG_UNPAIRED_SELECTED_CLASS);
}
else {
// Remove highlight
SVGUtil.removeCSSClass(extension, SEG_UNPAIRED_SELECTED_CLASS);
}
}
else {
int idx = policy.indexOfSegment(segment);
if(idx >= 0) {
String color = style.getColorSet(StyleLibrary.PLOT).getColor(idx);
extension.setAttribute(SVGConstants.SVG_STYLE_ATTRIBUTE, SVGConstants.CSS_FILL_PROPERTY + ":" + color);
}
else {
// Remove styling
extension.removeAttribute(SVGConstants.SVG_STYLE_ATTRIBUTE);
}
}
}
}
/**
* Creates a gradient over a set of colors
*
* @param shades number of colors in the gradient
* @param colors colors for the gradient
* @return array of colors for CSS
*/
protected String[] makeGradient(int shades, String[] colors) {
if(shades <= colors.length) {
return colors;
}
// Convert SVG colors into AWT colors for math
Color[] cols = new Color[colors.length];
for(int i = 0; i < colors.length; i++) {
cols[i] = SVGUtil.stringToColor(colors[i]);
if(cols[i] == null) {
throw new AbortException("Error parsing color: " + colors[i]);
}
}
// Step size
double increment = (cols.length - 1.) / shades;
String[] colorShades = new String[shades];
for(int s = 0; s < shades; s++) {
final int ppos = Math.min((int) Math.floor(increment * s), cols.length);
final int npos = Math.min((int) Math.ceil(increment * s), cols.length);
if(ppos == npos) {
colorShades[s] = colors[ppos];
}
else {
Color prev = cols[ppos];
Color next = cols[npos];
final double mix = (increment * s - ppos) / (npos - ppos);
final int r = (int) ((1 - mix) * prev.getRed() + mix * next.getRed());
final int g = (int) ((1 - mix) * prev.getGreen() + mix * next.getGreen());
final int b = (int) ((1 - mix) * prev.getBlue() + mix * next.getBlue());
colorShades[s] = SVGUtil.colorToString(((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF));
}
}
return colorShades;
}
protected Element drawClusteringInfo() {
Element thumbnail = SVGUtil.svgElement(svgp.getDocument(), SVGConstants.SVG_G_TAG);
// build thumbnail
int startRadius = 4;
int singleHeight = 12;
int margin = 4;
int radius = segments.getClusterings() * (singleHeight + margin) + startRadius;
SVGUtil.setAtt(thumbnail, SVGConstants.SVG_HEIGHT_ATTRIBUTE, radius);
for(int i = 0; i < segments.getClusterings(); i++) {
double innerRadius = i * singleHeight + margin * i + startRadius;
Element clr = SVGUtil.svgCircleSegment(svgp, radius - startRadius, radius - startRadius, Math.PI * 1.5, Math.PI * 0.5, innerRadius, innerRadius + singleHeight);
// FIXME: Use StyleLibrary
clr.setAttribute(SVGConstants.SVG_FILL_ATTRIBUTE, "#d4e4f1");
clr.setAttribute(SVGConstants.SVG_STROKE_ATTRIBUTE, "#a0a0a0");
clr.setAttribute(SVGConstants.SVG_STROKE_WIDTH_ATTRIBUTE, "1.0");
String labelText = segments.getClusteringDescription(i);
Element label = svgp.svgText(radius + startRadius, radius - innerRadius - startRadius, labelText);
thumbnail.appendChild(label);
thumbnail.appendChild(clr);
}
return thumbnail;
}
protected void segmentHover(Segment segment, int ringid, boolean active) {
if(active) {
// abort if this are the unclustered pairs
if(segment.isNone()) {
return;
}
if(LOG.isDebugging()) {
LOG.debug("Hover on segment: " + segment + " unpaired: " + segment.isUnpaired());
}
if(!segment.isUnpaired()) {
//
// STANDARD CLUSTER SEGMENT
// highlight all ring segments in this clustering and this cluster
//
// highlight all corresponding ring Segments
for(Entry> entry : segmentToElements.entrySet()) {
Segment other = entry.getKey();
// Same cluster in same clustering?
if(other.get(ringid) != segment.get(ringid)) {
continue;
}
Element ringSegment = entry.getValue().get(ringid);
SVGUtil.addCSSClass(ringSegment, CLR_HOVER_CLASS);
}
}
else {
//
// UNPAIRED SEGMENT
// highlight all ring segments in this clustering responsible for
// unpaired
// segment
//
// get the paired segments corresponding to the unpaired segment
List paired = segments.getPairedSegments(segment);
for(Segment other : paired) {
Element ringSegment = segmentToElements.get(other).get(ringid);
SVGUtil.addCSSClass(ringSegment, CLR_HOVER_CLASS);
}
}
}
else {
for(List elems : segmentToElements.values()) {
for(Element current : elems) {
SVGUtil.removeCSSClass(current, CLR_HOVER_CLASS);
}
}
}
}
protected void segmentClick(Segment segment, Event evt, boolean dblClick) {
MouseEvent mouse = (MouseEvent) evt;
// CTRL (add) pressed?
boolean ctrl = false;
if(mouse.getCtrlKey()) {
ctrl = true;
}
// Unselect others on double click
if(dblClick) {
policy.deselectAllSegments();
}
policy.select(segment, ctrl);
// update stylePolicy
context.setStylingPolicy(policy);
}
/**
* Proxy element to connect signals.
*
* @author Erich Schubert
*
* @apiviz.exclude
*/
private class SegmentListenerProxy implements EventListener {
/**
* Mouse double click time window in milliseconds
*
* TODO: does Batik have double click events?
*/
public static final int EVT_DBLCLICK_DELAY = 350;
/**
* Segment we are attached to
*/
private Segment id;
/**
* Segment ring we are
*/
private int ringid;
/**
* For detecting double clicks.
*/
private long lastClick = 0;
/**
* Constructor.
*
* @param id Segment id
* @param ringid Ring id
*/
public SegmentListenerProxy(Segment id, int ringid) {
super();
this.id = id;
this.ringid = ringid;
}
@Override
public void handleEvent(Event evt) {
if(SVGConstants.SVG_MOUSEOVER_EVENT_TYPE.equals(evt.getType())) {
segmentHover(id, ringid, true);
}
if(SVGConstants.SVG_MOUSEOUT_EVENT_TYPE.equals(evt.getType())) {
segmentHover(id, ringid, false);
}
if(SVGConstants.SVG_CLICK_EVENT_TYPE.equals(evt.getType())) {
// Check Double Click
boolean dblClick = false;
long time = java.util.Calendar.getInstance().getTimeInMillis();
if(time - lastClick <= EVT_DBLCLICK_DELAY) {
dblClick = true;
}
lastClick = time;
segmentClick(id, evt, dblClick);
}
}
}
}
} SegmentsStylingPolicy.java 0000664 0000000 0000000 00000021163 12657057427 0042263 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/pairsegments package de.lmu.ifi.dbs.elki.visualization.visualizers.pairsegments;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.TreeMap;
import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil;
import de.lmu.ifi.dbs.elki.database.ids.DBIDs;
import de.lmu.ifi.dbs.elki.database.ids.ModifiableDBIDs;
import de.lmu.ifi.dbs.elki.evaluation.clustering.pairsegments.Segment;
import de.lmu.ifi.dbs.elki.evaluation.clustering.pairsegments.Segments;
import de.lmu.ifi.dbs.elki.visualization.colors.ColorLibrary;
import de.lmu.ifi.dbs.elki.visualization.style.ClassStylingPolicy;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
/**
* Styling policy to communicate the segment selection to other visualizers.
*
* TODO: Remove "implements Result"
*
* @author Sascha Goldhofer
* @author Erich Schubert
* @since 0.5.0
*/
public class SegmentsStylingPolicy implements ClassStylingPolicy {
/**
* The segments we use for visualization
*/
protected final Segments segments;
/**
* Selected segments
*/
protected ArrayList selectedSegments = new ArrayList<>();
/**
* Segments indirectly selected
*/
protected TreeMap indirectSelections = new TreeMap<>();
/**
* Not selected IDs that will be drawn in default colors.
*/
protected ModifiableDBIDs unselectedObjects = DBIDUtil.newHashSet();
/**
* Color library (only used in compatibility mode)
*/
// TODO: move to abstract super class?
ColorLibrary colorset = null;
/**
* Constructor.
*
* @param segments Segments
*/
public SegmentsStylingPolicy(Segments segments) {
super();
this.segments = segments;
// get all selectable segments
for(Segment segment : segments) {
// store segmentID
if(!segment.isUnpaired()) {
// and store their get all objects
if(segment.getDBIDs() != null) {
unselectedObjects.addDBIDs(segment.getDBIDs());
}
}
}
}
/**
* Assign the style library, for compatibility color styling.
*
* FIXME: handle this more generally
*
* @param style Style library
*/
public void setStyleLibrary(StyleLibrary style) {
this.colorset = style.getColorSet(StyleLibrary.PLOT);
}
/**
* Test whether a segment is selected.
*
* @param segment Segment to test
* @return true when selected
*/
public boolean isSelected(Segment segment) {
return selectedSegments.contains(segment) || indirectSelections.containsValue(segment);
}
@Override
public int getStyleForDBID(DBIDRef id) {
Iterator s = selectedSegments.iterator();
for(int i = 0; s.hasNext(); i++) {
Segment seg = s.next();
DBIDs ids = seg.getDBIDs();
if(ids != null && ids.contains(id)) {
return i;
}
}
return -2;
}
@Override
public int getColorForDBID(DBIDRef id) {
int style = getStyleForDBID(id);
if(colorset != null) {
// FIXME: add caching
return SVGUtil.stringToColor(colorset.getColor(style)).getRGB();
}
else {
return 0;
}
}
@Override
// -2=grau, -1=schwarz, 0+=farben
public int getMinStyle() {
return -2;
}
@Override
public int getMaxStyle() {
return selectedSegments.size();
}
@Override
public DBIDIter iterateClass(int cnum) {
// unselected
if(cnum == -2) {
return unselectedObjects.iter();
}
else if(cnum == -1) {
return DBIDUtil.EMPTYDBIDS.iter();
}
// colors
DBIDs ids = selectedSegments.get(cnum).getDBIDs();
return (ids != null) ? ids.iter() : DBIDUtil.EMPTYDBIDS.iter();
}
@Override
public int classSize(int cnum) {
// unselected
if(cnum == -2) {
return unselectedObjects.size();
}
else if(cnum == -1) {
return 0;
}
// colors
DBIDs ids = selectedSegments.get(cnum).getDBIDs();
return (ids != null) ? ids.size() : 0;
}
/**
* Adds or removes the given segment to the selection. Depending on the
* clustering and cluster selected and the addToSelection option given, the
* current selection will be modified. This method is called by clicking on a
* segment and ring and the CTRL-button status.
*
* Adding selections does only work on the same clustering and cluster, else a
* new selection will be added.
*
* @param segment the selected element representing a segment ring (specific
* clustering)
* @param addToSelection flag for adding segment to current selection
*/
public void select(Segment segment, boolean addToSelection) {
// abort if segment represents pairs inNone. Would select all segments...
if(segment.isNone()) {
return;
}
if(!addToSelection) {
deselectAllSegments();
}
// get selected segments
if(segment.isUnpaired()) {
// check if all segments are selected
if(addToSelection) {
boolean allSegmentsSelected = true;
for(Segment other : segments.getPairedSegments(segment)) {
if(!isSelected(other)) {
allSegmentsSelected = false;
break;
}
}
// if all are selected, deselect all
if(allSegmentsSelected) {
deselectSegment(segment);
return;
}
}
if(isSelected(segment)) {
deselectSegment(segment);
}
else {
selectSegment(segment);
}
}
else {
// an object segment was selected
if(isSelected(segment)) {
deselectSegment(segment);
}
else {
selectSegment(segment);
}
}
}
/**
* Deselect all currently selected segments
*/
public void deselectAllSegments() {
while(selectedSegments.size() > 0) {
deselectSegment(selectedSegments.get(selectedSegments.size() - 1));
}
}
/**
* Deselect a segment
*
* @param segment Segment to deselect
*/
protected void deselectSegment(Segment segment) {
if(segment.isUnpaired()) {
ArrayList remove = new ArrayList<>();
// remove all object segments associated with unpaired segment from
// selection list
for(Entry entry : indirectSelections.entrySet()) {
if(entry.getValue() == segment) {
remove.add(entry.getKey());
}
}
for(Segment other : remove) {
indirectSelections.remove(other);
deselectSegment(other);
}
}
else {
// check if deselected object Segment has a unpaired segment highlighted
Segment unpaired = indirectSelections.get(segment);
if(unpaired != null) {
// remove highlight
deselectSegment(unpaired);
}
if(selectedSegments.remove(segment)) {
if(segment.getDBIDs() != null) {
unselectedObjects.addDBIDs(segment.getDBIDs());
}
}
}
}
/**
* Select a segment
*
* @param segment Segment to select
*/
protected void selectSegment(Segment segment) {
if(segment.isUnpaired()) {
// remember selected unpaired segment
for(Segment other : segments.getPairedSegments(segment)) {
indirectSelections.put(other, segment);
selectSegment(other);
}
}
else {
if(!selectedSegments.contains(segment)) {
selectedSegments.add(segment);
if(segment.getDBIDs() != null) {
unselectedObjects.removeDBIDs(segment.getDBIDs());
}
}
}
}
/**
* Get the index of a selected segment.
*
* @param segment Segment to find
* @return Index, or -1
*/
public int indexOfSegment(Segment segment) {
return selectedSegments.indexOf(segment);
}
@Override
public String getMenuName() {
return "Pair segments styling policy";
}
} package-info.java 0000775 0000000 0000000 00000002035 12657057427 0040270 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/pairsegments /**
*
Visualizers for inspecting cluster differences using pair counting segments.
*/
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.lmu.ifi.dbs.elki.visualization.visualizers.pairsegments; 0000775 0000000 0000000 00000000000 12657057427 0034171 5 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/parallel AbstractParallelVisualization.java 0000664 0000000 0000000 00000011512 12657057427 0043036 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/parallel package de.lmu.ifi.dbs.elki.visualization.visualizers.parallel;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
import de.lmu.ifi.dbs.elki.database.relation.Relation;
import de.lmu.ifi.dbs.elki.visualization.VisualizationItem;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.gui.VisualizationPlot;
import de.lmu.ifi.dbs.elki.visualization.projections.Projection;
import de.lmu.ifi.dbs.elki.visualization.projections.ProjectionParallel;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGPlot;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
import de.lmu.ifi.dbs.elki.visualization.visualizers.AbstractVisualization;
/**
* Abstract base class for parallel visualizations.
*
* @author Robert Rödler
* @author Erich Schubert
* @since 0.5.0
*
* @param Data type in relation
*/
public abstract class AbstractParallelVisualization extends AbstractVisualization {
/**
* The current projection
*/
final protected ProjectionParallel proj;
/**
* The representation we visualize
*/
final protected Relation relation;
/**
* margin
*/
final double[] margins;
/**
* Space between two axes
*/
protected double axsep;
/**
* viewbox size
*/
final double[] size;
/**
* Constructor.
*
* @param task Visualization task
* @param plot Plot to draw to
* @param width Embedding width
* @param height Embedding height
* @param proj Projection
*/
public AbstractParallelVisualization(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj) {
super(task, plot, width, height);
this.proj = (ProjectionParallel) proj;
this.relation = task.getRelation();
margins = new double[] { 0.05 * StyleLibrary.SCALE, 0.1 * StyleLibrary.SCALE, 0.05 * StyleLibrary.SCALE, 0.1 * StyleLibrary.SCALE };
double ratio = (width * StyleLibrary.SCALE - margins[0] - margins[2]) / (height * StyleLibrary.SCALE - margins[1] - margins[3]);
size = new double[] { ratio * StyleLibrary.SCALE, StyleLibrary.SCALE };
recalcAxisPositions();
}
@Override
public void fullRedraw() {
this.layer = setupCanvas(svgp, this.proj, getWidth(), getHeight());
}
/**
* Utility function to setup a canvas element for the visualization.
*
* @param svgp Plot element
* @param proj Projection to use
* @param width Width
* @param height Height
* @return wrapper element with appropriate view box.
*/
public Element setupCanvas(SVGPlot svgp, ProjectionParallel proj, double width, double height) {
Element layer = SVGUtil.svgElement(svgp.getDocument(), SVGConstants.SVG_G_TAG);
final String transform = SVGUtil.makeMarginTransform(width, height, size[0], size[1], margins[0], margins[1], margins[2], margins[3]);
SVGUtil.setAtt(layer, SVGConstants.SVG_TRANSFORM_ATTRIBUTE, transform);
return layer;
}
/**
* Get width of main canvas.
*
* @return Width
*/
protected double getSizeX() {
return size[0];
}
protected double getSizeY() {
return size[1];
}
protected double getMarginLeft() {
return margins[0];
}
protected double getMarginTop() {
return margins[1];
}
/**
* Distance between axes.
*
* @return Axis separation
*/
protected double getAxisSep() {
return axsep;
}
/**
* Recalculate axis positions, in particular after projection changes.
*/
private void recalcAxisPositions() {
axsep = size[0] / (proj.getVisibleDimensions() - 1.);
}
/**
* Get the position of visible axis d
*
* @param d Visible axis number
* @return Position
*/
protected double getVisibleAxisX(double d) {
return d * axsep;
}
@Override
public void visualizationChanged(VisualizationItem item) {
super.visualizationChanged(item);
if(item == proj) {
recalcAxisPositions();
svgp.requestRedraw(this.task, this);
return;
}
}
} AxisReorderVisualization.java 0000664 0000000 0000000 00000026404 12657057427 0042053 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/parallel package de.lmu.ifi.dbs.elki.visualization.visualizers.parallel;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventListener;
import org.w3c.dom.events.EventTarget;
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.Hierarchy;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTree;
import de.lmu.ifi.dbs.elki.visualization.VisualizerContext;
import de.lmu.ifi.dbs.elki.visualization.css.CSSClass;
import de.lmu.ifi.dbs.elki.visualization.gui.VisualizationPlot;
import de.lmu.ifi.dbs.elki.visualization.projections.Projection;
import de.lmu.ifi.dbs.elki.visualization.projector.ParallelPlotProjector;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGArrow;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGPlot;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
import de.lmu.ifi.dbs.elki.visualization.visualizers.AbstractVisFactory;
import de.lmu.ifi.dbs.elki.visualization.visualizers.Visualization;
/**
* Interactive SVG-Elements for reordering the axes.
*
* @author Robert Rödler
* @author Erich Schubert
* @since 0.5.5
*
* @apiviz.stereotype factory
* @apiviz.uses Instance oneway - - «create»
*/
public class AxisReorderVisualization extends AbstractVisFactory {
/**
* A short name characterizing this Visualizer.
*/
private static final String NAME = "Dimension Ordering Tool";
/**
* Constructor, adhering to
*/
public AxisReorderVisualization() {
super();
}
@Override
public Visualization makeVisualization(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj) {
return new Instance(task, plot, width, height, proj);
}
@Override
public void processNewResult(VisualizerContext context, Object start) {
Hierarchy.Iter> it = VisualizationTree.filter(context, start, ParallelPlotProjector.class);
for(; it.valid(); it.advance()) {
ParallelPlotProjector> p = it.get();
final VisualizationTask task = new VisualizationTask(NAME, context, p.getRelation(), p.getRelation(), AxisReorderVisualization.this);
task.level = VisualizationTask.LEVEL_INTERACTIVE;
task.addFlags(VisualizationTask.FLAG_NO_THUMBNAIL | VisualizationTask.FLAG_NO_EXPORT);
context.addVis(p, task);
}
}
/**
* Instance for a particular plot.
*
* @author Robert Rödler
* @author Erich Schubert
*/
public class Instance extends AbstractParallelVisualization {
/**
* Generic tags to indicate the type of element. Used in IDs, CSS-Classes
* etc.
*/
public static final String SELECTDIMENSIONORDER = "SelectDimensionOrder";
/**
* CSS class for a tool button
*/
public static final String SDO_BUTTON = "DObutton";
/**
* CSS class for a button border
*/
public static final String SDO_BORDER = "DOborder";
/**
* CSS class for a button cross
*/
public static final String SDO_ARROW = "DOarrow";
/**
* Currently selected dimension. Use -1 to not have a dimension selected.
*/
private int selecteddim = -1;
/**
* Constructor.
*
* @param task VisualizationTask
* @param plot Plot to draw to
* @param width Embedding width
* @param height Embedding height
* @param proj Projection
*/
public Instance(VisualizationTask task, VisualizationPlot plot, double width, double height, Projection proj) {
super(task, plot, width, height, proj);
addListeners();
}
@Override
public void fullRedraw() {
super.fullRedraw();
addCSSClasses(svgp);
final int dim = proj.getVisibleDimensions();
final double controlsize = 0.025 * getSizeY();
final double buttonsize = 0.75 * controlsize;
final double padding = 0.125 * controlsize;
final double arrowsize = .75 * buttonsize;
final double ypos = getSizeY() + getMarginTop() * .5 + controlsize;
final double spacing = 0.9 * controlsize;
Element back = svgp.svgRect(-controlsize * .5, ypos, getSizeX() + controlsize, controlsize);
SVGUtil.addCSSClass(back, SELECTDIMENSIONORDER);
layer.appendChild(back);
if(selecteddim < 0) {
// Nothing selected
for(int i = 0; i < dim; i++) {
final double xpos = getVisibleAxisX(i);
if(i > 0) {
Element arrow = SVGArrow.makeArrow(svgp, SVGArrow.LEFT, xpos - spacing, ypos + controlsize * .5, arrowsize);
SVGUtil.addCSSClass(arrow, SDO_ARROW);
layer.appendChild(arrow);
Element button = svgp.svgRect(xpos - spacing - buttonsize * .5, ypos + padding, buttonsize, buttonsize);
SVGUtil.addCSSClass(button, SDO_BUTTON);
addEventListener(button, i, SVGArrow.LEFT);
layer.appendChild(button);
}
{
Element arrow = SVGArrow.makeArrow(svgp, SVGArrow.DOWN, xpos, ypos + controlsize * .5, arrowsize);
SVGUtil.addCSSClass(arrow, SDO_ARROW);
layer.appendChild(arrow);
Element button = svgp.svgRect(xpos - buttonsize * .5, ypos + padding, buttonsize, buttonsize);
SVGUtil.addCSSClass(button, SDO_BUTTON);
addEventListener(button, i, SVGArrow.DOWN);
layer.appendChild(button);
}
if(i < dim - 1) {
Element arrow = SVGArrow.makeArrow(svgp, SVGArrow.RIGHT, xpos + spacing, ypos + controlsize * .5, arrowsize);
SVGUtil.addCSSClass(arrow, SDO_ARROW);
layer.appendChild(arrow);
Element button = svgp.svgRect(xpos + spacing - buttonsize * .5, ypos + padding, buttonsize, buttonsize);
SVGUtil.addCSSClass(button, SDO_BUTTON);
addEventListener(button, i, SVGArrow.RIGHT);
layer.appendChild(button);
}
}
}
else {
for(int i = 0; i < dim; i++) {
{
Element arrow = SVGArrow.makeArrow(svgp, SVGArrow.DOWN, getVisibleAxisX(i), ypos + controlsize * .5, arrowsize);
SVGUtil.addCSSClass(arrow, SDO_ARROW);
layer.appendChild(arrow);
Element button = svgp.svgRect(getVisibleAxisX(i) - buttonsize * .5, ypos + padding, buttonsize, buttonsize);
SVGUtil.addCSSClass(button, SDO_BUTTON);
addEventListener(button, i, SVGArrow.DOWN);
layer.appendChild(button);
}
if(i > 0.) {
Element arrow = SVGArrow.makeArrow(svgp, SVGArrow.UP, getVisibleAxisX(i - .5), ypos + controlsize * .5, arrowsize);
SVGUtil.addCSSClass(arrow, SDO_ARROW);
layer.appendChild(arrow);
Element button = svgp.svgRect(getVisibleAxisX(i - .5) - buttonsize * .5, ypos + padding, buttonsize, buttonsize);
SVGUtil.addCSSClass(button, SDO_BUTTON);
addEventListener(button, i, SVGArrow.UP);
layer.appendChild(button);
}
}
}
}
/**
* Add an event listener to the Element
*
* @param tag Element to add the listener
* @param i represented axis
*/
private void addEventListener(final Element tag, final int i, final SVGArrow.Direction j) {
EventTarget targ = (EventTarget) tag;
targ.addEventListener(SVGConstants.SVG_EVENT_CLICK, new EventListener() {
@Override
public void handleEvent(Event evt) {
if(selecteddim < 0) {
switch(j){
case DOWN:
selecteddim = i;
break;
case LEFT:
int prev = i - 1;
while(prev >= 0 && !proj.isAxisVisible(prev)) {
prev -= 1;
}
proj.swapAxes(i, prev);
break;
case RIGHT:
int next = i + 1;
while(next < proj.getInputDimensionality() - 1 && !proj.isAxisVisible(next)) {
next += 1;
}
proj.swapAxes(i, next);
break;
default:
break;
}
}
else {
switch(j){
case DOWN:
proj.swapAxes(selecteddim, i);
selecteddim = -1;
break;
case UP:
if(selecteddim != i) {
proj.moveAxis(selecteddim, i);
}
selecteddim = -1;
break;
default:
break;
}
}
// Notify
context.visChanged(proj);
}
}, false);
}
/**
* Adds the required CSS-Classes
*
* @param svgp SVG-Plot
*/
private void addCSSClasses(SVGPlot svgp) {
final StyleLibrary style = context.getStyleLibrary();
if(!svgp.getCSSClassManager().contains(SELECTDIMENSIONORDER)) {
CSSClass cls = new CSSClass(this, SELECTDIMENSIONORDER);
cls.setStatement(SVGConstants.CSS_OPACITY_PROPERTY, 0.1);
cls.setStatement(SVGConstants.CSS_FILL_PROPERTY, SVGConstants.CSS_BLUE_VALUE);
svgp.addCSSClassOrLogError(cls);
}
if(!svgp.getCSSClassManager().contains(SDO_BORDER)) {
CSSClass cls = new CSSClass(this, SDO_BORDER);
cls.setStatement(SVGConstants.CSS_STROKE_PROPERTY, SVGConstants.CSS_GREY_VALUE);
cls.setStatement(SVGConstants.CSS_STROKE_WIDTH_PROPERTY, style.getLineWidth(StyleLibrary.PLOT) / 3.0);
cls.setStatement(SVGConstants.CSS_FILL_PROPERTY, SVGConstants.CSS_NONE_VALUE);
svgp.addCSSClassOrLogError(cls);
}
if(!svgp.getCSSClassManager().contains(SDO_BUTTON)) {
CSSClass cls = new CSSClass(this, SDO_BUTTON);
cls.setStatement(SVGConstants.CSS_OPACITY_PROPERTY, 0.01);
cls.setStatement(SVGConstants.CSS_FILL_PROPERTY, SVGConstants.CSS_GREY_VALUE);
cls.setStatement(SVGConstants.CSS_CURSOR_PROPERTY, SVGConstants.CSS_POINTER_VALUE);
svgp.addCSSClassOrLogError(cls);
}
if(!svgp.getCSSClassManager().contains(SDO_ARROW)) {
CSSClass cls = new CSSClass(this, SDO_ARROW);
cls.setStatement(SVGConstants.CSS_STROKE_PROPERTY, SVGConstants.CSS_DARKGREY_VALUE);
cls.setStatement(SVGConstants.CSS_STROKE_WIDTH_PROPERTY, style.getLineWidth(StyleLibrary.PLOT) / 3);
cls.setStatement(SVGConstants.CSS_FILL_PROPERTY, SVGConstants.CSS_BLACK_VALUE);
svgp.addCSSClassOrLogError(cls);
}
}
}
} AxisVisibilityVisualization.java 0000664 0000000 0000000 00000024264 12657057427 0042602 0 ustar 00root root 0000000 0000000 elki-release0.7.1/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/visualizers/parallel package de.lmu.ifi.dbs.elki.visualization.visualizers.parallel;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see