├── .gitattributes
├── .gitignore
├── .gitmodules
├── .idea
├── Visualization.iml
├── deployment.xml
├── inspectionProfiles
│ ├── Project_Default.xml
│ └── profiles_settings.xml
├── misc.xml
├── modules.xml
├── remote-mappings.xml
├── vcs.xml
└── webServers.xml
├── Conda_linux64_spec_file.txt
├── Conda_package_list.txt
├── Conda_win64_spec_file.txt
├── FullRequirements.txt
├── FullSetup.bat
├── FullSetup.sh
├── README.md
├── UpdateApplication.bat
├── UpdateApplication.sh
├── Vis_OrigColors.png
├── Visualizer
├── MouseInteraction.py
├── Scripts
│ ├── GetData.bat
│ └── Setup.bat
├── TaskList.txt
├── Vis.ico
├── Visualizer.py
├── Window.py
├── colors.py
├── data.py
├── events
│ ├── __init__.py
│ ├── event.py
│ └── listener.py
├── exception_handler.py
├── frames
│ ├── ListFrame.py
│ ├── MatplotlibFrame.py
│ ├── PMIPlot.py
│ ├── QtMatplotlib.py
│ ├── RelationTypeFrame.py
│ ├── TimeSeriesFrame.py
│ ├── TimeSeriesVisualizer.py
│ ├── TopRelations.py
│ ├── VisualizerFrame.py
│ ├── VisualizerWidget.py
│ ├── __init__.py
│ ├── matplotlib_util.py
│ └── preprocessor_controller.py
├── main.py
├── menu.py
├── menus
│ ├── __init__.py
│ └── pmi_menu.py
├── models
│ ├── __init__.py
│ └── list_model.py
├── pmi_corr_plot.png
├── qt_test.py
├── requirements.txt
├── setup.py
├── startup.py
├── templates
│ └── template.tex
├── ui
│ ├── GeneratePy.bat
│ ├── GeneratePy.sh
│ ├── __init__.py
│ ├── main_window.py
│ ├── main_window.ui
│ ├── pmi_control_panel_horiz.py
│ ├── pmi_control_panel_horiz.ui
│ ├── pmi_control_panel_vert.py
│ ├── pmi_control_panel_vert.ui
│ ├── preprocessor_form.py
│ ├── preprocessor_form.ui
│ ├── preprocessor_run.py
│ ├── preprocessor_run.ui
│ ├── relation_types.py
│ ├── relation_types.ui
│ ├── relation_types_tabs.py
│ ├── relation_types_tabs.ui
│ ├── top_relations.py
│ ├── top_relations.ui
│ ├── topics_list.py
│ ├── topics_list.ui
│ ├── visualizer.py
│ └── visualizer.ui
└── widgets
│ ├── ColoredBox.py
│ ├── ListBoxColumn.py
│ └── __init__.py
└── examples
├── acl.jsonlist.gz
├── acl.jsonlist.short
├── acl.p
├── nips.jsonlist.gz
└── nips_t.p
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.gz filter=lfs diff=lfs merge=lfs -text
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 6/16/2017
3 | # Created by https://www.gitignore.io/api/python
4 |
5 | ## Python
6 | # Byte-compiled / optimized / DLL files
7 | __pycache__/
8 | *.py[cod]
9 | *$py.class
10 |
11 | # virtualenv
12 | .venv
13 | venv/
14 | ENV/
15 |
16 | ## Visual Studio
17 | # User-specific files
18 | *.suo
19 | *.user
20 | *.userosscache
21 | *.sln.docstates
22 |
23 | ## Custom
24 |
25 | output/
26 | *.p
27 |
28 | ### PyCharm ###
29 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
30 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
31 |
32 | # User-specific stuff:
33 | .idea/**/workspace.xml
34 | .idea/**/tasks.xml
35 | .idea/dictionaries
36 |
37 | # Sensitive or high-churn files:
38 | .idea/**/dataSources/
39 | .idea/**/dataSources.ids
40 | .idea/**/dataSources.xml
41 | .idea/**/dataSources.local.xml
42 | .idea/**/sqlDataSources.xml
43 | .idea/**/dynamic.xml
44 | .idea/**/uiDesigner.xml
45 |
46 | ## Custom files
47 | data/
48 | *.whl
49 | Visualizer/acl_example/
50 | idea_rel_dist/
51 | *.log
52 |
53 | Application/
54 | build/
55 |
56 | *.tgz
57 | *.zip
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "idea_relations"]
2 | path = idea_relations
3 | url = git@github.com:nwrush/idea_relations.git
4 | branch = master
5 |
--------------------------------------------------------------------------------
/.idea/Visualization.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/.idea/deployment.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/remote-mappings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/webServers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Conda_linux64_spec_file.txt:
--------------------------------------------------------------------------------
1 | # This file may be used to create an environment using:
2 | # $ conda create --name --file
3 | # platform: linux-64
4 | cycler=0.10.0=py35_0
5 | dbus=1.10.20=0
6 | expat=2.1.0=0
7 | fontconfig=2.12.1=3
8 | freetype=2.5.5=2
9 | glib=2.50.2=1
10 | gst-plugins-base=1.8.0=0
11 | gstreamer=1.8.0=0
12 | icu=54.1=0
13 | jpeg=9b=0
14 | libffi=3.2.1=1
15 | libgcc=5.2.0=0
16 | libgfortran=3.0.0=1
17 | libiconv=1.14=0
18 | libpng=1.6.27=0
19 | libxcb=1.12=1
20 | libxml2=2.9.4=0
21 | matplotlib=2.0.2=np113py35_0
22 | mkl=2017.0.3=0
23 | nltk=3.2.4=py35_0
24 | numpy=1.13.1=py35_0
25 | openssl=1.0.2l=0
26 | pandas=0.20.3=py35_0
27 | patsy=0.4.1=py35_0
28 | pcre=8.39=1
29 | pip=9.0.1=py35_1
30 | pyparsing=2.2.0=py35_0
31 | pyqt=5.6.0=py35_2
32 | python=3.5.4=0
33 | python-dateutil=2.6.1=py35_0
34 | pytz=2017.2=py35_0
35 | qt=5.6.2=5
36 | readline=6.2=2
37 | requests=2.14.2=py35_0
38 | scipy=0.19.1=np113py35_0
39 | seaborn=0.8=py35_0
40 | setuptools=27.2.0=py35_0
41 | sip=4.18=py35_0
42 | six=1.10.0=py35_0
43 | sqlite=3.13.0=0
44 | statsmodels=0.8.0=np113py35_0
45 | tk=8.5.18=0
46 | wheel=0.29.0=py35_0
47 | xz=5.2.2=1
48 | zlib=1.2.8=3
49 |
--------------------------------------------------------------------------------
/Conda_package_list.txt:
--------------------------------------------------------------------------------
1 | matplotlib
2 | nltk
3 | numpy
4 | scipy
5 | pyqt # Version 5
6 | seaborn
7 |
--------------------------------------------------------------------------------
/Conda_win64_spec_file.txt:
--------------------------------------------------------------------------------
1 | # This file may be used to create an environment using:
2 | # $ conda create --name --file
3 | # platform: win-64
4 | cycler=0.10.0=py36_0
5 | icu=57.1=vc14_0
6 | jpeg=9b=vc14_0
7 | libpng=1.6.27=vc14_0
8 | matplotlib=2.0.2=np113py36_0
9 | mkl=2017.0.3=0
10 | nltk=3.2.4=py36_0
11 | numpy=1.13.1=py36_0
12 | openssl=1.0.2l=vc14_0
13 | pandas=0.20.3=py36_0
14 | patsy=0.4.1=py36_0
15 | pip=9.0.1=py36_1
16 | pyparsing=2.2.0=py36_0
17 | pyqt=5.6.0=py36_2
18 | python=3.6.2=0
19 | python-dateutil=2.6.1=py36_0
20 | pytz=2017.2=py36_0
21 | qt=5.6.2=vc14_6
22 | requests=2.14.2=py36_0
23 | scipy=0.19.1=np113py36_0
24 | seaborn=0.8=py36_0
25 | setuptools=27.2.0=py36_1
26 | sip=4.18=py36_0
27 | six=1.10.0=py36_0
28 | statsmodels=0.8.0=np113py36_0
29 | tk=8.5.18=vc14_0
30 | vs2015_runtime=14.0.25420=0
31 | wheel=0.29.0=py36_0
32 | zlib=1.2.8=vc14_3
33 |
--------------------------------------------------------------------------------
/FullRequirements.txt:
--------------------------------------------------------------------------------
1 | # Visualizaer
2 | cycler>=0.10.0
3 | matplotlib>=2.0.2
4 | numpy>=1.13.0
5 | pyparsing>=2.2.0
6 | python-dateutil>=2.6.0
7 | pytz>=2017.2
8 | six>=1.10.0
9 | PyQt5>=5.9
10 |
11 | # Idea Relations
12 | nltk>=3.2.1
13 | pandas>=0.18.1
14 | seaborn>=0.7.1
15 |
--------------------------------------------------------------------------------
/FullSetup.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | setlocal
4 |
5 | Set PythonPath=PATH TO PYTHON HERE
6 |
7 | git submodule init
8 | git submodule update
9 |
10 | Set ROOT=%CD%
11 |
12 | Set AppPath=Application
13 | Set VisPath=Visualizer
14 |
15 | IF NOT EXIST %PythonPath% (
16 | ECHO Python executable at %PythonPath% was not found
17 | EXIT /B 1
18 | )
19 |
20 | :: This script should be executed from where you want to root the application
21 |
22 | mkdir "%AppPath%"
23 |
24 | :: Install the visualizer
25 | xcopy "%VisPath%\*.py" "%AppPath%\"
26 | xcopy "%VisPath%\frames\*.py" "%AppPath%\frames\"
27 | xcopy "%VisPath%\widgets\*.py" "%AppPath%\widgets\"
28 | xcopy "%VisPath%\menus\*.py" "%AppPath%\menus\"
29 | xcopy "%VisPath%\events\*.py" "%AppPath%\events\"
30 | xcopy "%VisPath%\ui\*.py" "%AppPath%\ui\"
31 | xcopy "%VisPath%\models\*.py" "%AppPath%\models\"
32 |
33 | :: Install the preprocessor
34 | mkdir "%AppPath%\idea_relations"
35 |
36 | xcopy "idea_relations\*.py" "%AppPath%\idea_relations\"
37 | xcopy "idea_relations\templates" "%AppPath%\idea_relations\templates\"
38 | xcopy "idea_relations\*.bat" "%AppPath%\idea_relations\"
39 | xcopy "idea_relations\*.sh" "%AppPath%\idea_relations\"
40 |
41 |
42 | :: Install the virtual environment
43 | copy FullRequirements.txt %AppPath%\FullRequirements.txt
44 | copy *.whl "%AppPath%\"
45 |
46 | endlocal & Set AppPath=%AppPath% & Set PythonPath=%PythonPath%
47 | cd %AppPath%
48 |
49 | virtualenv --python=%PythonPath% venv
50 | call .\venv\Scripts\activate.bat
51 |
52 | pip install "numpy-1.13.3+mkl-cp35-cp35m-win_amd64.whl"
53 | pip install "scipy-1.0.0-cp35-cp35m-win_amd64.whl"
54 | pip install -r FullRequirements.txt
55 |
56 | Set "AppPath="
57 | Set "PythonPath="
58 |
--------------------------------------------------------------------------------
/FullSetup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | PythonPath="$(which python3)"
4 | VenvPath="$(which virtualenv)" # Ideally the same one provided by the python installation you pointed to above
5 |
6 | git submodule init
7 | git submodule update
8 |
9 | ROOT=$(pwd)
10 |
11 | AppPath=Application
12 | VisPath=Visualizer
13 |
14 | # Check executables for existance
15 | if [[ ! -f "$PythonPath" ]] || [[ ! -x "$PythonPath" ]]
16 | then
17 | echo Couldn\'t locate python executable at $PythonPath
18 | exit 1
19 | else
20 | echo Using python executable at $PythonPath
21 | fi
22 |
23 | if [[ ! -f "$VenvPath" ]] || [[ ! -x "$VenvPath" ]]
24 | then
25 | echo Couldn\'t locate virtualenv at $VenvPath
26 | exit 1
27 | else
28 | echo Using virtualenv at $VenvPath
29 | fi
30 |
31 | mkdir $AppPath
32 | mkdir $AppPath/frames
33 | mkdir $AppPath/widgets
34 | mkdir $AppPath/menus
35 | mkdir $AppPath/events
36 | mkdir $AppPath/ui
37 | mkdir $AppPath/models
38 |
39 |
40 | cp $VisPath/*.py $AppPath
41 | cp $VisPath/frames/*.py $AppPath/frames/
42 | cp $VisPath/widgets/*.py $AppPath/widgets/
43 | cp $VisPath/menus/*.py $AppPath/menus/
44 | cp $VisPath/events/*.py $AppPath/events/
45 | cp $VisPath/ui/*.py $AppPath/ui
46 | cp $VisPath/models/*.py $AppPath/models
47 |
48 | mkdir $AppPath/idea_relations
49 |
50 | cp idea_relations/*.py $AppPath/idea_relations/
51 | cp -r idea_relations/templates $AppPath/idea_relations/templates/
52 | cp idea_relations/*.bat $AppPath/idea_relations/
53 | cp idea_relations/*.sh $AppPath/idea_relations/
54 |
55 | cp FullRequirements.txt $AppPath/FullRequirements.txt
56 |
57 | cd $AppPath
58 |
59 | $VenvPath --python=$PythonPath venv
60 | source venv/bin/activate
61 | pip install --upgrade pip
62 |
63 | pip install -r FullRequirements.txt
64 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Visualization
2 |
3 | This project is still in active development, but is mostly stable. Various features are subject to appear or disappear with little/no notice.
4 |
5 | ## Current Release
6 |
7 | v1.0 - [Link](https://github.com/nwrush/Visualization/releases)
8 |
9 | ## About
10 |
11 | This project builds on the work done by Chenhao Tan and Dallas Card in [this paper](https://chenhaot.com/pages/idea-relations.html). This tool provides a way to visualize text interactively using the relations outlined in the paper.
12 |
13 | # Installation
14 | Installing has been tested on Windows (7 and higher) (64-bit), Linux (Centos7), and some version of OSX. For convenience install scripts are provided for Windows and Linux.
15 | Binaries are also provided for Windows and Linux.
16 |
17 | After running any of the installation methods, if you've never used NLTK you will need to download the NLTK stopword corpus. Activate the virtualenv for the application and run `python -m nltk.downloader stopwords`
18 |
19 | ### Requirements
20 | - Python3 (only tested on 3.5 and higher)
21 | - A display
22 | - Running over a x-server is possibly but does not look good
23 |
24 | ## Installing from the repo
25 |
26 | ### Linux Installation
27 | 1. Download or clone the repo
28 | 2. Change the value of the variables $PYTHONPATH and $VenvPath to point to your system python installation and virtualenv
29 | 3. Run `./FullSetup.sh`
30 | - This will create the application in a new folder called Application
31 | 4. Activate the virtualenv (Application/venv)
32 | 5. Run the visualizer with: `python Visualizer.py`
33 |
34 | ### Windows Installation
35 | 1. Download or clone the repo
36 | 2. Change the value of the variable PythonPath to point to your system python installation
37 | 3. Run `FullSetup.bat`
38 | - This will create the application in a new folder called Application
39 | 4. Activate the virtualenv
40 | - If you called FullSetup.bat from the command line, the virtualenv may already be active
41 | 5. Run the visualizer with: `python Visualizer.py`
42 |
43 | ### Manual Installation
44 | 1. Download or clone the repo
45 | 2. Run: `git submodule init` and then `git submodule update`
46 | 3. Create a new folder where you want to install the application
47 | 4. From the folder Visualizer, copy all .py files and all folders to your application folder
48 | 6. Copy the top level idea_relations folder into the application folder
49 | 7. Create a virtual environment containing the packages listed in the FullRequirements.txt file
50 | 8. Activate the virtual environment and run the visualizer with `python Visualizer.py`
51 |
52 | ### Anaconda Installation
53 | 1. Follow the Manual Installation instructions up to step 6
54 | 2. Instead of creating a python virtualenv, you can create an anaconda environment containing the packages in Conda_package_list.txt
55 | - Linux and Windows users can try to use the appropriate spec file
56 | 3. Run the program the same as the manual installation instructions
57 |
58 | ## Packaged Installation
59 |
60 | The application is distributed in three forms. A standalone Windows binary, standalone Linux binary, and the plain python files.
61 | Both the Windows and Linux binary should run without any issue, just double click on the executable (Visualizer.exe) to run.
62 | The Linux binary should function on any Linux system (including OSX), but has only been tested on Centos 7.
63 |
64 | For the python files, you must have python version >3.5 available on your system. Installation is similar to the manual installation. Unpack the zip file and follow the manual installation instructions above from step 7.
65 |
66 | Because of the much larger size of the Windows and Linux binaries, it is probably better to use the python version, especially if you already have Python 3 on your system.
67 |
68 | As of right now, the prepacked installations cannot run the preprocessor due to bugs with scipy. A fix will potentially be available late December. Using a virtualenv with the raw python files works fine though.
69 |
70 | ## Note for Windows installation
71 |
72 | On Windows, it may be difficult/impossible to install scipy using pip. To get around that we recommend downloading a prebuilt wheel for numpy and scipy from [this](https://www.lfd.uci.edu/~gohlke/pythonlibs/) website. You will need wheels for both numpy and scipy. Download the appropriate wheel for your system (matching python version and architecture).
73 | If you're installing the program from the repo using the installation scripts, place them in the root directory for the repo, and edit lines 52 and 53 of FullSetup.py to have the correct file names. If you're installing from the zipped python files, copy them wherever you unpacked the code and install them using pip into your virtualenv. You must install them
74 | before you install packages from FullRequirements.txt otherwise pip will install numpy from the web and then be unable to install scipy.
75 | If you're installing from the standalone Windows binary, you don't need to do anything.
76 |
77 | # Usage
78 |
79 | The preprocessor can be run in two modes, Keywords and Topics. In keywords, the system will take two files a "input" file and a "background" file. The system calculates the prevelance of each word in both files, and creates the topic list from the top n words/phrases in the input file that aren't in the background file. While not necessary, the background file should be in the same domain as the input file for more accurate results.
80 | In Topic mode the system will run LDA on the input file using Mallet to "learn" the top 50 topics on its own. This doesn't require a background file, but does take significantly longer (~30 minutes on the demo dataset).
81 | Further details for how the topics are selected is available in [this paper](https://chenhaot.com/pages/idea-relations.html).
82 |
83 | After running the preprocessor to get the relationships a new tab will open with the plot of the relationships between topics. Each dot on the graph represents a single topic/topic pair, if there are more than 1000 pairs then 1000 items will be selected randomly to populate the graph. Selecting an item will display the frequency time series for each relation as well as populating the 'Top Relation' filters.
84 |
85 | On the left side of the window is the filter tab area, here you can filter down the visible topics. Selecting items in the ideas tab causes all relationship involving the selected ideas to populate the graph. In the types tab, relations are sorted by their type and strength, selecting a relationship here causes all relations involving either topic to appear on the graph. The other two tabs here 'Top Relation 1' and 'Top Relation 2' simply display a sorted list of the strength of all relations each selected topic has.
86 |
87 | You can save visualizations for later use from the File menu, this saves you from having to wait for the preprocessor to run again. Additionally, you can load multiple visualizations into multiple tabs. In the visualization menu you can save images of the current PMI/correlation plot and the time series plot, the images saved are exactly what appears on the screen when you hit save.
88 |
89 | ## Input file format
90 |
91 | Input files should be given as jsonlists, one document per line. The only two fields needed are date and text.
92 | The date will be parsed using the [python dateutil library](http://dateutil.readthedocs.io/en/stable/parser.html#dateutil.parser.parse) with a default date of datetime(1,1,1) and all other arguemnts at their defaults. It will be converted to a string first as well. The text should be just the full text of the document properly quoted. For examples see acl.jsonlist in the included [example data folder](./examples).
93 | The datafile can be compressed with gz before being passed in.
94 |
95 | Two example visualizations are provided for you, acl.p and nips_t.p. The first one is the acl dataset in acl.jsonlist.gz processed using keywords with the nips dataset as the background file, the second one is the nips dataset processed using topics.
96 |
97 | ## Preprocessor options
98 |
99 | You must pass the preprocessor 3 options, exploration name which determines what the visualization will be called (mainly setting the tab title), the number of ideas (which tells the preprocessor how many ideas to look for), and time grouping (year, month, day) to set the time scale the preprocessor uses when grouping articles. There are also 3 optional options, Tokenize, Lemmatize, and No Stop Words. These will perform the relevant preprocessing to the data before searching for topics. Additionally, you can use the advanced options to force the preprocessor to save it's intermediate output data somewhere else if you wanted. The intermediate data isn't terrible useful/readable though.
100 |
101 | 
102 |
--------------------------------------------------------------------------------
/UpdateApplication.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | git submodule update
4 |
5 | Set Loc=%CD%
6 |
7 | setlocal
8 |
9 | Set ROOT=%~dp0
10 | echo %ROOT%
11 | cd %ROOT%
12 |
13 | Set AppPath=Application
14 | Set VisPath=Visualizer
15 |
16 | :: This script re-copies all python files to the application folder
17 |
18 | :: Update the visualizer
19 | xcopy /Y "%VisPath%\*.py" "%AppPath%\"
20 | xcopy /Y "%VisPath%\frames\*.py" "%AppPath%\frames\"
21 | xcopy /Y "%VisPath%\widgets\*.py" "%AppPath%\widgets\"
22 | xcopy /Y "%VisPath%\menus\*.py" "%AppPath%\menus\"
23 | xcopy /Y "%VisPath%\events\*.py" "%AppPath%\events\"
24 | xcopy /Y "%VisPath%\ui\*.py" "%AppPath%\ui\"
25 | xcopy /Y "%VisPath%\models\*.py" "%AppPath%\models\"
26 |
27 | :: Update the preprocessor
28 |
29 | xcopy /Y "idea_relations\*.py" "%AppPath%\idea_relations\"
30 | xcopy /Y "idea_relations\templates" "%AppPath%\idea_relations\templates\"
31 | xcopy /Y "idea_relations\*.bat" "%AppPath%\idea_relations\"
32 | xcopy /Y "idea_relations\*.sh" "%AppPath%\idea_relations\"
33 |
34 | endlocal
35 |
36 | cd %Loc%
37 |
38 | set "Loc="
39 |
--------------------------------------------------------------------------------
/UpdateApplication.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | git submodule update
4 |
5 | ROOT=$(pwd)
6 |
7 | AppPath=Application
8 | VisPath=Visualizer
9 |
10 | # Update Visualizer
11 | cp -u $VisPath/*.py $AppPath
12 | cp -u $VisPath/frames/*.py $AppPath/frames/
13 | cp -u $VisPath/widgets/*.py $AppPath/widgets/
14 | cp -u $VisPath/menus/*.py $AppPath/menus/
15 | cp -u $VisPath/events/*.py $AppPath/events/
16 | cp -u $VisPath/ui/*.py $AppPath/ui
17 | cp -u $VisPath/models/*.py $AppPath/models
18 |
19 | # Update Idea Relations
20 | cp -u idea_relations/*.py $AppPath/idea_relations/
21 | cp -u -r idea_relations/templates $AppPath/idea_relations/templates/
22 | cp -u idea_relations/*.bat $AppPath/idea_relations/
23 | cp -u idea_relations/*.sh $AppPath/idea_relations/
24 |
--------------------------------------------------------------------------------
/Vis_OrigColors.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nwrush/Visualization/bc134aa02156956ea3644b34d491da9f0e9f63ae/Vis_OrigColors.png
--------------------------------------------------------------------------------
/Visualizer/MouseInteraction.py:
--------------------------------------------------------------------------------
1 | class MouseInteract:
2 | def __init__(self, canvas, plot, select_callback=None):
3 | self.canvas = canvas
4 | self.plot = plot
5 |
6 | self.connect()
7 |
8 | self.press = None
9 | self.prev_selected_ind = None
10 |
11 | self._select_callback = select_callback
12 |
13 | def connect(self):
14 | self.canvas.mpl_connect('button_press_event', self.on_click)
15 | self.canvas.mpl_connect('button_release_event', self.on_release)
16 | self.canvas.mpl_connect('motion_notify_event', self.on_motion)
17 | self.canvas.mpl_connect('pick_event', self.on_select)
18 |
19 | def on_click(self, event):
20 | print("ouch")
21 | self.press = event.xdata, event.ydata
22 |
23 | def on_release(self, event):
24 | pass
25 |
26 | def on_motion(self, event):
27 | if self.press is None:
28 | return
29 |
30 | def on_select(self, event):
31 | print("Selected something")
32 | ind = event.ind[0]
33 |
34 | if self.prev_selected_ind is not None:
35 | self.plot._facecolors[self.prev_selected_ind] = (0, 0, 1, 1)
36 | self.plot._edgecolors[self.prev_selected_ind] = (0, 0, 1, 1)
37 |
38 | self.plot._facecolors[ind] = (1,0,0,1)
39 | self.plot._edgecolors[ind] = (1,0,0,1)
40 |
41 | if self._select_callback is not None:
42 | self._select_callback(event)
43 |
44 | self.canvas.draw()
45 |
46 | self.prev_selected_ind = ind
47 |
--------------------------------------------------------------------------------
/Visualizer/Scripts/GetData.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | if not exist "..\processed_data" mkdir ..\processed_data
4 |
5 | pscp -P 1255 nikko@zin.cs.washington.edu:/home/nikko/visualization/Visualization/idea_relations/*.p ..\processed_data\.
--------------------------------------------------------------------------------
/Visualizer/Scripts/Setup.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | cd ..
4 |
5 | virtualenv --python=C:\Users\Nikko\AppData\Local\Programs\Python\Python35\python.exe venv
6 | call .\venv\Scripts\activate.bat
7 |
8 | pip install -r requirements.txt
--------------------------------------------------------------------------------
/Visualizer/TaskList.txt:
--------------------------------------------------------------------------------
1 | --Priority
2 |
3 | --TODO
4 | 7/2/17: Test multiple screen sizes
5 | 7/5/17: Don't assume with the datestamps and step sizes
6 | 7/6/17: Run in a profiler to see what's taking time on start
7 | 7/19/17: Make the settings for the file/directory dialog boxes more reasonable
8 | 7/28/17: Improve event handling system
9 | 8/10/17: Updated README with note about development status, install instructions, example data files
10 | 8/10/17: Document required file format
11 | 8/29/17: Provide way of filtering or sorting the top relation lists
12 |
13 | --Bugfix
14 | 7/28/17: Selecting a single relation and then a pair that contains the single causes strange behavior (behavior does not persist when rerun, could be VS lag bug)
15 |
16 | --Wishlist
17 | 7/5/17: More logical way to decide which element was picked in case of conflict
18 | 7/5/17: Drag box selection of points with zooming?
19 | 7/5/17: Parameter object that can be passed to frames to specify format (visual styles)| 7/17/17 Exists on LayoutConfiguration branch but is rather messy
20 | 8/8/17: Interactive date range (idea_relations.idea_relations:70) has arguments
21 | 8/10/17: Custom word list
22 | 8/10/17: Graph based layout on PMI or KL divergence between topics
23 |
24 |
25 | --Done (please mention the commit name here too)
26 | 7/2/17: Refactor code to make it easier to work with | 7/5/17 (abf2d55)
27 | 7/2/17: MouseInteraction should know what color to change points too | 7/5/17 (abf2d55) MouseInteraction is obsolete
28 | 7/2/17: Fix the correlation text overwriting when you select a new point (part of refactoring code into classes) | 7/5/17 (f855889) Sure, that "works"
29 | 7/7/17: Custom Multicolumn listboxes | 7/9/17 (dadf23b)
30 | 7/7/17: Refactor TimeSeriesFrame so it controls the graphing of plots instead of the PMI graph | 7/10/17 (329cfc4)
31 | 7/2/17: Layout all six frames in the tk full screen widget | 7/11/17 (4fbcc56)
32 | 7/10/17: Git commit hashes in the tasklist don't match up | 7/11/17 (3f36d95)
33 | 7/7/17: Verify correlation coefficients | 7/11/17 (NOCOMMIT)
34 | 7/13/17: Button names aren't correct, (tryst and friends are flipped) | 7/14/17 (f37289f)
35 | 7/8/17: Synchronize the scrolling of ListBoxColumn lists | 7/14/17 (4931ce0)
36 | 7/2/17: Find a better way to layout the time series plot correlation number | 7/17/17 (8bc42d5) TimeSeries control panel still could use work
37 | 7/19/17: Don't freeze the UI when you run the subprocess | 7/20/17 (2a3afb8)
38 | 7/7/17: Allow dynamically set (user defined) colors for plots | 7/27/17 (0389392)
39 | 7/27/17: Loading a data file when one is already loaded fails when trying to create new fonts | 7/28/17 (ac4bc09)
40 | 7/27/17: List highlighting | 7/28/17 (788591f)
41 | 7/27/17: Clear time series and and selected relations when new point is selected | 7/28/17 (788591f)
42 | 7/28/17: Move GUI root code into class | 8/7/17 (74645b5)
43 | 7/27/17: Column labels for the listboxes | 8/7/17 (74645b5)
44 | 7/2/17: Better looking frames | 8/7/17 (74645b5)
45 | 7/27/17: Mac scroll wheel bug | 8/7/17 (74645b5) Assumed fixed
46 | 7/27/17: Grid resizing | Obsolete with (d4409f1)
47 | 8/10/17: Clean up the preprocessor form to avoid showing extraneous fields | 8/10/17 (c32581e)
48 | 8/10/17: Validate the preprocessor form | 8/10/17 (c32581e)
49 | 8/10/17: Progress bar show incremental status | 8/11/17 (a4e7d98)
50 | 8/10/17: Anaconda support | 8/18/17 (fa473ec)
51 | 8/10/17: Save images of graphs to file | 8/18/17 (d4c1e58)
--------------------------------------------------------------------------------
/Visualizer/Vis.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nwrush/Visualization/bc134aa02156956ea3644b34d491da9f0e9f63ae/Visualizer/Vis.ico
--------------------------------------------------------------------------------
/Visualizer/Visualizer.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 6/21/2017
3 |
4 | # region Imports
5 | import logging
6 | import platform
7 | import sys
8 |
9 | FORMAT = "%(asctime)s %(levelname)8s:[%(filename)s:%(lineno)s - %(funcName)20s()] %(message)s"
10 | logging.basicConfig(level=logging.DEBUG,
11 | format=FORMAT,
12 | datefmt='%m-%d %H:%M:%S',
13 | filename='./Visualizer.log',
14 | filemode='w')
15 |
16 | import PyQt5.QtGui as QtGui
17 | import PyQt5.QtWidgets as QtWidgets
18 | import matplotlib
19 | matplotlib.use("Qt5Agg")
20 |
21 | import exception_handler
22 | import data
23 | from frames.preprocessor_controller import PreprocessorController
24 | from frames.VisualizerWidget import VisualizerWidget
25 | from ui import main_window
26 | # endregion
27 |
28 | logging.info("Application Startup")
29 | logging.info(platform.uname())
30 | logging.info(platform.platform())
31 | logging.info(platform.python_version())
32 |
33 | version = platform.win32_ver()
34 | if not version[0] == '':
35 | logging.info(version)
36 |
37 | version = platform.mac_ver()
38 | if not version[0] == '':
39 | logging.info(version)
40 |
41 | """
42 | GUI creation
43 | """
44 |
45 |
46 | class Application(QtWidgets.QMainWindow):
47 |
48 | def __init__(self, data_manager=None):
49 | super(Application, self).__init__()
50 |
51 | self.ui = main_window.Ui_mainWindow()
52 | self.ui.setupUi(self)
53 |
54 | self.ui.tabWidget.tabCloseRequested.connect(self._close_tab)
55 |
56 | self.main_widget = self.ui.main_widget
57 | self.main_widget.setFocus()
58 | self.setCentralWidget(self.main_widget)
59 |
60 | self._tabs = []
61 |
62 | self._init_menu()
63 |
64 | self._preprocess_widget = None
65 | self._load_preprocessor()
66 |
67 | self._tabs.append(self._preprocess_widget)
68 |
69 | if data_manager is not None:
70 | self._add_tab(data_manager, 1)
71 |
72 | def _load_preprocessor(self):
73 | self._preprocess_widget = PreprocessorController(self.main_widget, self._preprocessor_callback)
74 | self.ui.tabWidget.insertTab(0, self._preprocess_widget, "Preprocessor")
75 |
76 | def _load_visualizer(self):
77 | self._visualizer_widget = VisualizerWidget(self.main_widget, self._data_manager)
78 | self.ui.tabWidget.insertTab(1, self._visualizer_widget, self._data_manager.name)
79 |
80 | def _init_menu(self):
81 | # File Menu
82 | self.ui.actionOpen.triggered.connect(self._open_visualization)
83 | self.ui.actionSave.triggered.connect(self._save_visualization)
84 |
85 | # Visualization Menu
86 | self.ui.tabWidget.currentChanged.connect(self._tab_changed)
87 | self.ui.actionSave_PMI.triggered.connect(self._save_pmi)
88 | self.ui.actionSave_TS.triggered.connect(self._save_ts)
89 | self.ui.actionSave_Both.triggered.connect(self._save_both)
90 |
91 | def _add_tab(self, tab_data, index):
92 | widget = VisualizerWidget(self.main_widget, tab_data)
93 | self.ui.tabWidget.insertTab(index, widget, tab_data.name)
94 | self._tabs = self._tabs[:index] + [widget] + self._tabs[index:]
95 | self.ui.tabWidget.setCurrentIndex(index)
96 |
97 | def _processed_file(self, fname):
98 | data_manager = data.load_data(fname)
99 | if data_manager is not None:
100 | self._add_tab(data_manager, len(self._tabs))
101 |
102 | def _preprocessor_callback(self, return_code):
103 | if return_code == 0:
104 | self._processed_file(self._preprocess_widget.output_name)
105 |
106 | def _open_visualization(self):
107 | dialog = QtWidgets.QFileDialog(self)
108 | dialog.setFileMode(QtWidgets.QFileDialog.ExistingFiles)
109 | dialog.setNameFilters(["Processed data file (*.p)", "All Files (*)"])
110 | dialog.exec()
111 |
112 | fnames = dialog.selectedFiles()
113 | if fnames:
114 | for fname in fnames:
115 | self._processed_file(fname)
116 |
117 | def _save_visualization(self):
118 | current_tab = self._tabs[self.ui.tabWidget.currentIndex()]
119 | if isinstance(current_tab, PreprocessorController):
120 | return
121 |
122 | dialog = QtWidgets.QFileDialog(self)
123 | dialog.setFileMode(QtWidgets.QFileDialog.AnyFile)
124 | dialog.setNameFilters(["Processed data file (*.p)", "All Files (*)"])
125 | dialog.setAcceptMode(QtWidgets.QFileDialog.AcceptSave)
126 | dialog.setDefaultSuffix(".p")
127 | dialog.exec()
128 |
129 | fname = dialog.selectedFiles()[0]
130 | success = current_tab.save_data(fname)
131 | if not success:
132 | QtWidgets.QMessageBox.about(self, "Save Error",
133 | "An error occured saving the file\nCheck the log for more details")
134 |
135 | def _tab_changed(self, index):
136 | if index >= len(self._tabs):
137 | self.ui.visualizationMenu.setEnabled(False)
138 | else:
139 | self.ui.visualizationMenu.setEnabled(isinstance(self._tabs[index], VisualizerWidget))
140 |
141 | def _save_pmi(self):
142 | self.ui.tabWidget.currentWidget().save_pmi()
143 |
144 | def _save_ts(self):
145 | self.ui.tabWidget.currentWidget().save_ts()
146 |
147 | def _save_both(self):
148 | self.ui.tabWidget.currentWidget().save_both()
149 |
150 | def _close_tab(self, index):
151 | if isinstance(self._tabs[index], PreprocessorController):
152 | return
153 | self.ui.tabWidget.removeTab(index)
154 | del self._tabs[index]
155 |
156 | def kill_preprocessor(self):
157 | self._preprocess_widget.kill()
158 |
159 |
160 | def is_square_matrix(a):
161 | return a.shape[0] == a.shape[1]
162 |
163 |
164 | def main(fname=None):
165 | data_manager = None
166 | if fname is not None:
167 | data_manager = data.load_data(fname)
168 |
169 | qApp = QtWidgets.QApplication(sys.argv)
170 | logging.info(qApp.primaryScreen().physicalSize())
171 | window = Application(data_manager)
172 | window.show()
173 | qApp.exec()
174 | logging.info("Goodbye")
175 |
176 |
177 | if __name__ == "__main__":
178 | main()
179 |
--------------------------------------------------------------------------------
/Visualizer/Window.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 7/2/2017
3 | # The Tk window root
4 |
5 | import tkinter as tk
6 | from tkinter import ttk
7 |
8 | class Window(object):
9 | """description of class"""
10 |
11 | def __init__(self):
12 | self.root = tk.Tk()
13 |
14 | self.root.protocol("WM_DELETE_WINDOW", self.__close_window_callback)
15 |
16 | def start(self):
17 | self.root.mainloop()
18 |
19 | def __close_window_callback(self):
20 | self.root.quit()
21 | self._close()
22 |
23 | def _close(self):
24 | """Called after quiting tk"""
25 | pass
26 |
27 |
28 | if __name__ == "__main__":
29 | window = Window()
30 | window.start()
--------------------------------------------------------------------------------
/Visualizer/colors.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 7/25/2017
3 |
4 | import matplotlib.cm as cm
5 | import matplotlib.colors
6 |
7 |
8 | class PMIColormap(matplotlib.colors.Colormap):
9 |
10 | def __init__(self, name, color, N=256):
11 | super(PMIColormap, self).__init__(name=name, N=N)
12 |
13 | self._color_map = None
14 | self._base_color = None
15 | self._saturation_max = None
16 |
17 | if isinstance(color, matplotlib.colors.Colormap):
18 | self._color_map = color
19 | if isinstance(color, str) and color in cm.cmap_d:
20 | self._color_map = cm.get_cmap(color)
21 | else:
22 | self._base_color = color
23 | self._saturation_max = matplotlib.colors.rgb_to_hsv(color)[1]
24 |
25 | def _resample(self, lutsize):
26 | super(PMIColormap, self)._resample(lutsize)
27 |
28 | def _init(self):
29 | super(PMIColormap, self)._init()
30 |
31 | def __call__(self, dist, *args, **kwargs):
32 | if self._color_map is not None:
33 | return self._color_map.__call__(dist, *args, **kwargs)
34 |
35 | hsv_value = matplotlib.colors.rgb_to_hsv(self._base_color)
36 |
37 | hsv_value[1] = self._saturation_max * dist
38 |
39 | rgb = matplotlib.colors.hsv_to_rgb(hsv_value)
40 | r, g, b = tuple(rgb)
41 | r = int(r)
42 | g = int(g)
43 | b = int(b)
44 | assert 0 <= r <= 255
45 | assert 0 <= g <= 255
46 | assert 0 <= b <= 255
47 | if kwargs['bytes']:
48 | return r, g, b, 255.0
49 | else:
50 | return r / 255, g / 255, b / 255, 1.0
51 |
--------------------------------------------------------------------------------
/Visualizer/data.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 7/10/2017
3 |
4 | # Last update 9/4/17
5 |
6 | import logging
7 | import os
8 | import os.path
9 | import pickle
10 |
11 | import numpy as np
12 |
13 |
14 | def reverse_dict(input_dict):
15 | output = dict()
16 | for key, value in input_dict.items():
17 | if value in output:
18 | logging.warn("Warning: Duplicate key will be overwritten in new dictionary")
19 | output[value] = key
20 | return output
21 |
22 |
23 | def is_square(a):
24 | row, col = a.shape
25 | return row == col
26 |
27 |
28 | def load_data(fname):
29 | if not os.path.isfile(fname):
30 | logging.info("Data file {0} doesn't exist".format(fname))
31 | return None
32 |
33 | return pickle.load(open(fname, 'rb'))
34 |
35 |
36 | def save_data(fname, data):
37 | try:
38 | f = open(fname, 'wb')
39 | pickle.dump(data, f)
40 | f.flush()
41 | f.close()
42 | except Exception as ex:
43 | logging.error("Failure while saving data")
44 | logging.exception(ex)
45 | return False
46 | return True
47 |
48 |
49 | class Data:
50 | def __init__(self, args, pmi_matrix, ts_correlation_matrix, ts_matrix, idea_names, x_vals,
51 | name="Visualization"):
52 |
53 | self._args = args
54 | self._is_keywords = args.option.upper() == "KEYWORDS"
55 | self.pmi = pmi_matrix
56 | self.ts_correlation = ts_correlation_matrix
57 | self.ts_matrix = ts_matrix
58 | self.idea_names = idea_names # Goes from indexes to text
59 | self.x_values = x_vals
60 |
61 | self.idea_numbers = reverse_dict(self.idea_names) # Goes from text to indexes
62 | self.num_ideas = len(self.idea_names)
63 |
64 | self.strength_matrix = self._get_strength_matrix()
65 |
66 | self.relation_types = ("Friends", "Tryst", "Head-To-Head", "Arms-Race") # Layout the relation in quadrant order
67 |
68 | self.name = name if name is not None else "Visualization"
69 |
70 | def _get_strength_matrix(self):
71 | assert self.pmi.shape == self.ts_correlation.shape
72 | assert is_square(self.pmi)
73 |
74 | a = np.multiply(self.pmi, self.ts_correlation)
75 |
76 | lower_indexes = np.tril_indices(self.pmi.shape[0])
77 | a[lower_indexes] = np.nan
78 | return a
79 |
80 | def get_idea_names(self, indexes):
81 | if isinstance(indexes, int):
82 | return self.idea_names[indexes]
83 |
84 | try:
85 | names = list()
86 | for index in indexes:
87 | names.append(self.idea_names[index])
88 | return names
89 | except TypeError as err:
90 | logging.error(err)
91 |
92 | return None
93 |
94 | TOPIC_DISPLAY_WIDTH = 3
95 |
96 | def get_display_idea_names(self, indexes):
97 | if self._is_keywords:
98 | return self.get_idea_names(indexes)
99 |
100 | if isinstance(indexes, int):
101 | full_name = self.idea_names[indexes]
102 | return ','.join(full_name.split(',')[:self.TOPIC_DISPLAY_WIDTH]) + '...'
103 |
104 | try:
105 | names = list()
106 | first = True
107 | for index in indexes:
108 | full_name = self.idea_names[index]
109 | short_name = ','.join(full_name.split(',')[:self.TOPIC_DISPLAY_WIDTH]) + '...'
110 | names.append(short_name)
111 | return names
112 | except TypeError as err:
113 | logging.error(err)
114 | return None
115 |
--------------------------------------------------------------------------------
/Visualizer/events/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nwrush/Visualization/bc134aa02156956ea3644b34d491da9f0e9f63ae/Visualizer/events/__init__.py
--------------------------------------------------------------------------------
/Visualizer/events/event.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 7/28/2017
3 |
4 |
5 | class Event(object):
6 | """description of class"""
7 |
8 | def __init__(self):
9 | pass
10 |
--------------------------------------------------------------------------------
/Visualizer/events/listener.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 7/28/2017
3 |
4 |
5 | class Listener(object):
6 | def __init__(self, *handlers):
7 | self._handlers = set(handlers)
8 |
9 | def add_handler(self, func):
10 | self._handlers.add(func)
11 |
12 | def has_handler(self, func):
13 | return func in self._handlers
14 |
15 | def remove_handler(self, func):
16 | self._handlers.discard(func)
17 |
18 | add = add_handler
19 | remove = remove_handler
20 |
21 | def invoke_empty(self):
22 | for func in self._handlers:
23 | func()
24 |
25 | def invoke(self, event):
26 | for func in self._handlers:
27 | code = func.__code__
28 | if code.co_argcount == 0:
29 | func()
30 | elif code.co_argcount == 1 and code.co_varnames == ('self',):
31 | func()
32 | else:
33 | func(event)
34 |
--------------------------------------------------------------------------------
/Visualizer/exception_handler.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 8/3/2017
3 |
4 | import logging
5 | import sys
6 | import traceback
7 |
8 |
9 | def custom_handler(type, value, tback):
10 | logging.error(''.join(traceback.format_exception(type, value, tback)))
11 |
12 | sys.__excepthook__(type, value, traceback)
13 |
14 | sys.excepthook = custom_handler
15 |
--------------------------------------------------------------------------------
/Visualizer/frames/ListFrame.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 7/6/2017
3 |
4 | import PyQt5.QtCore as QtCore
5 | from PyQt5.QtCore import Qt
6 |
7 | from events import event, listener
8 | from frames.VisualizerFrame import VisualizerFrame
9 | from models.list_model import ListModel
10 | from ui import topics_list
11 |
12 |
13 | class ListFrame(VisualizerFrame):
14 | """description of class"""
15 | def __init__(self, parent, data=None):
16 | super(ListFrame, self).__init__(parent, data_manager=data)
17 |
18 | self.ui = topics_list.Ui_topicsList()
19 | self.ui.setupUi(self)
20 |
21 | self._filter = QtCore.QSortFilterProxyModel()
22 | self._model = ListModel(self.data.idea_names.values(), self)
23 |
24 | self._onselect_listener = listener.Listener()
25 |
26 | self._filter.setSourceModel(self._model)
27 | self.ui.listWidget.setModel(self._filter)
28 |
29 | self.ui.listWidget.selectionModel().selectionChanged.connect(self._on_select_model)
30 | self.ui.filterText.textEdited.connect(self._filter.setFilterFixedString)
31 |
32 | def add_select_listener(self, func):
33 | self._onselect_listener.add(func)
34 |
35 | def has_select_listener(self, func):
36 | return self._onselect_listener.has_handler(func)
37 |
38 | def remove_select_listener(self, func):
39 | self._onselect_listener.remove(func)
40 |
41 | def clear_selection(self):
42 | self.ui.listWidget.clearSelection()
43 |
44 | def _on_select_model(self, selected, deselected):
45 | indexes = set()
46 | for index in self.ui.listWidget.selectedIndexes():
47 | indexes.add(self.data.idea_numbers[index.data(Qt.DisplayRole)])
48 |
49 | eve = event.Event()
50 | eve.selected_indexes = indexes
51 | self._onselect_listener.invoke(eve)
52 |
--------------------------------------------------------------------------------
/Visualizer/frames/MatplotlibFrame.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 7/2/2017
3 |
4 | import PyQt5.QtCore as QtCore
5 | import PyQt5.QtWidgets as QtWidgets
6 |
7 | from matplotlib.figure import Figure
8 | from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
9 |
10 |
11 | class QMatplotlib(FigureCanvasQTAgg):
12 | """Frame specifically for displaying matplotlib graphs"""
13 |
14 | def __init__(self, figure=None, parent=None, width=None, height=None, dpi=None):
15 |
16 | if figure is not None:
17 | self._figure = figure
18 | else:
19 | if width or height or dpi is None:
20 | self._figure = Figure()
21 | else:
22 | self._figure = Figure(figsize=(width, height), dpi=dpi)
23 |
24 | self._axes = self._figure.gca()
25 |
26 | super(QMatplotlib, self).__init__(self._figure)
27 | self.setParent(parent)
28 | self.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
29 | # self._set_size()
30 | self.updateGeometry()
31 |
32 | self.setFocusPolicy(QtCore.Qt.ClickFocus)
33 |
34 | self._allow_redraw = True
35 | self._redraw_requested = False
36 |
37 | def _set_size(self):
38 | fig_w, fig_h = map(int, self._figure.get_size_inches() * self._figure.dpi)
39 | self.setMaximumSize(fig_w, fig_h)
40 | self.setMinimumSize(fig_w, fig_h)
41 |
42 | @property
43 | def axes(self):
44 | return self._axes
45 |
46 | @property
47 | def canvas(self):
48 | return self._figure.canvas
49 |
50 | def get_figure(self):
51 | return self._figure
52 |
53 | def redraw(self):
54 | if self._allow_redraw:
55 | self.draw()
56 | else:
57 | self._redraw_requested = True
58 |
59 | def allow_redraw(self):
60 | self._allow_redraw = True
61 | if self._redraw_requested:
62 | self.redraw()
63 |
64 | def prevent_redraw(self):
65 | self._allow_redraw = False
66 | self._redraw_requested = False
67 |
68 | def grow_plot(self, delta):
69 | size = self.figure.get_size_inches()
70 | size[0] = size[0] + delta/self.figure.dpi
71 | self.figure.set_size_inches(size)
72 | # self._set_size()
73 | # self.updateGeometry()
74 | self.redraw()
75 |
76 | def set_plot_size(self, width):
77 | size = self.figure.get_size_inches()
78 | size[0] = width/self.figure.dpi
79 | self.figure.set_size_inches(size)
80 |
--------------------------------------------------------------------------------
/Visualizer/frames/PMIPlot.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 7/5/2017
3 |
4 | import logging
5 | import math
6 |
7 | import PyQt5.QtWidgets as QtWidgets
8 | import PyQt5.QtGui as QtGui
9 |
10 | import matplotlib.cm as cm
11 | import matplotlib.colors as colors
12 | import matplotlib.patches as mpatches
13 | import numpy as np
14 |
15 | import colors as visualizer_colors
16 | from events import listener
17 | from frames.MatplotlibFrame import QMatplotlib
18 | from frames.VisualizerFrame import VisualizerFrame
19 | from ui import pmi_control_panel_vert
20 | from ui import pmi_control_panel_horiz
21 | from frames.matplotlib_util import Utils
22 |
23 | # These values are added to the x_lim and y_lim to ensure that all points are drawn on the screen
24 | X_BUFFER = 0.1
25 | Y_BUFFER = 0.1
26 |
27 |
28 | class PMIPlot(VisualizerFrame, Utils):
29 | def __init__(self, parent, data):
30 | super(PMIPlot, self).__init__(parent=parent, data_manager=data)
31 |
32 | # self.layout = QtWidgets.QHBoxLayout(self)
33 | self.layout = QtWidgets.QVBoxLayout(self)
34 |
35 | self._mpl_container = QtWidgets.QWidget(self)
36 | self._mpl_layout = QtWidgets.QHBoxLayout(self._mpl_container)
37 | self._old_mpl_width = self._mpl_container.width()
38 |
39 | self._mpl = QMatplotlib(parent=self._mpl_container)
40 | self._mpl_layout.addWidget(self._mpl)
41 | self._mpl.prevent_redraw()
42 |
43 | self.layout.addWidget(self._mpl_container)
44 |
45 | self.axes = self._mpl.axes
46 | self.canvas = self._mpl.canvas
47 |
48 | self._x_lim = [np.amin(data.ts_correlation) - X_BUFFER, np.amax(data.ts_correlation) + X_BUFFER]
49 | self._y_lim = [np.amin(data.pmi) - Y_BUFFER, np.amax(data.pmi) + Y_BUFFER]
50 |
51 | self._control_panel = QtWidgets.QWidget(self)
52 | self._control_panel_ui = pmi_control_panel_horiz.Ui_pmi_control_panel()
53 | self._control_panel_ui.setupUi(self._control_panel)
54 | self.layout.addWidget(self._control_panel)
55 |
56 | self._init_handlers()
57 |
58 | self.plot_data = None
59 | self.idea_indexes = None
60 | self.x_values = None
61 | self.y_values = None
62 | self.sample_size = None
63 |
64 | # TODO: Allow these to be set dynamically
65 | self.selected_color = "Black"
66 | # Colors should be a list of four matplotlib color maps or rgb tuples
67 | self._colors = ["Greens",
68 | "Oranges",
69 | "Reds",
70 | "Blues"]
71 | self._legend_proxies = list()
72 |
73 | self._prev_selected_ind = None
74 | self._prev_annotation = None
75 |
76 | self._on_select_listener = listener.Listener(self._change_selected_color, self._annotate_selected)
77 | self._on_reset_listener = listener.Listener(self._reset_graph)
78 | self._on_color_changed_listener = listener.Listener()
79 |
80 | self.on_select_clear_listener = listener.Listener(self._clear_selection)
81 |
82 | self._normalizer = colors.Normalize(vmin=0, vmax=1, clip=True)
83 | self._update_colors(self._colors)
84 | self.add_color_changed_listener(self._color_plot)
85 |
86 | self._setup_control_panel()
87 |
88 | self._has_data = False
89 |
90 | self.axes.legend(handles=self._legend_proxies, loc="best")
91 |
92 | self._mpl.allow_redraw()
93 |
94 | def resizeEvent(self, eve):
95 | super(PMIPlot, self).resizeEvent(eve)
96 | if eve.oldSize().width() == -1 or eve.oldSize().height() == -1:
97 | self._old_mpl_width = self._mpl_container.width()
98 | return
99 |
100 | # self._mpl.grow_plot(self._mpl_container.width()-self._old_mpl_width)
101 | self._mpl.set_plot_size(self._mpl_container.width())
102 |
103 | def _setup_control_panel(self):
104 | # self._gear_icon = images.load_image("gear-2-16.gif")
105 | control_panel_ui = self._control_panel_ui
106 | control_panel_ui.resetButton.clicked.connect(self._on_reset)
107 |
108 | def _init_plot_(self):
109 | """Reset the axes for plotting"""
110 | self.axes.clear()
111 | self._has_data = False
112 | self.axes.set_title("PMI vs. Cooccurrence")
113 | self.axes.set_xlabel("Prevalence Correlation")
114 | self.axes.set_ylabel("Cooccurrence")
115 | self.axes.set_xlim(self._x_lim)
116 | self.axes.set_ylim(self._y_lim)
117 |
118 | def _update_colors(self, color_spec):
119 | """
120 | Takes a sequence of 4 color tuples, builds the color maps, if
121 | the plot data isn't none will modify the plot colors
122 | """
123 |
124 | self._colors = color_spec
125 |
126 | self._color_maps = [visualizer_colors.PMIColormap("PMIFriend", color_spec[0]),
127 | visualizer_colors.PMIColormap("PMITryst", color_spec[1]),
128 | visualizer_colors.PMIColormap("PMIHeadToHead", color_spec[2]),
129 | visualizer_colors.PMIColormap("PMIArmsRace", color_spec[3])]
130 |
131 | self.color_mappers = [cm.ScalarMappable(norm=self._normalizer, cmap=self._color_maps[0]),
132 | cm.ScalarMappable(norm=self._normalizer, cmap=self._color_maps[1]),
133 | cm.ScalarMappable(norm=self._normalizer, cmap=self._color_maps[2]),
134 | cm.ScalarMappable(norm=self._normalizer, cmap=self._color_maps[3])]
135 |
136 | self.color_samples = dict()
137 | self._legend_proxies = []
138 | for mapper, name in zip(self.color_mappers, self.data.relation_types):
139 | rgba = mapper.to_rgba(0.7, bytes=True)
140 | self.color_samples[name] = rgba
141 | self._legend_proxies.append(mpatches.Patch(color=[i/255 for i in rgba], label=name))
142 |
143 | self._on_color_changed()
144 | self._mpl.redraw()
145 |
146 | def plot(self, sample=None):
147 | # Generate a list of all strictly upper triangular indexes
148 | self.sample_size = sample
149 | points = []
150 | for i in range(0, self.data.num_ideas):
151 | for j in range(i + 1, self.data.num_ideas):
152 | points.append((i, j))
153 |
154 | self._plot(points, sample)
155 |
156 | def _plot(self, points, sample=None):
157 |
158 | if sample is not None and isinstance(sample, int):
159 | if 0 < sample and sample < len(points):
160 | indexes = np.random.choice(len(points), sample, replace=False)
161 | points = [points[i] for i in indexes]
162 | assert len(points) == sample
163 |
164 | xs, ys = [], []
165 | for i, j in points:
166 | if np.isnan(self.data.pmi[i, j]) or np.isnan(self.data.ts_correlation[i, j]):
167 | continue
168 | if np.isinf(self.data.pmi[i, j]) or np.isinf(self.data.ts_correlation[i, j]):
169 | continue
170 |
171 | xs.append(self.data.ts_correlation[i, j])
172 | ys.append(self.data.pmi[i, j])
173 |
174 | self._init_plot_()
175 | self.plot_data = self.axes.scatter(xs, ys, picker=True)
176 | self.axes.legend(handles=self._legend_proxies, loc="best")
177 |
178 | self.idea_indexes = points
179 | self.x_values = xs
180 | self.y_values = ys
181 |
182 | self._has_data = True
183 |
184 | self._color_plot()
185 |
186 | def _color_plot(self):
187 | colors = []
188 | for x, y in zip(self.x_values, self.y_values):
189 | distance = math.sqrt(x ** 2 + y ** 2)
190 | if x >= 0 and y >= 0: # First quadrant, someone has to select zero
191 | colors.append(self.color_mappers[0].to_rgba(distance))
192 | elif x < 0 and y > 0: # Second quadrant
193 | colors.append(self.color_mappers[1].to_rgba(distance))
194 | elif x < 0 and y < 0: # Third quadrant
195 | colors.append(self.color_mappers[2].to_rgba(distance))
196 | elif x > 0 and y < 0: # Fourth quadrant
197 | colors.append(self.color_mappers[3].to_rgba(distance))
198 | else:
199 | logging.error("({x}, {y}) couldn't be mapped onto grid".format(x=x, y=y))
200 | colors.append((0, 0, 0, 0))
201 | self.plot_data.set_color(colors)
202 | self._point_colors = colors
203 |
204 | self.axes.legend(handles=self._legend_proxies, loc="best")
205 |
206 | def _init_handlers(self):
207 | self.canvas.mpl_connect('button_press_event', self._on_click)
208 | self.canvas.mpl_connect('pick_event', self._on_select)
209 |
210 | def _on_click(self, event):
211 | pass
212 |
213 | # Event listener functions
214 | def add_select_listener(self, func):
215 | self._on_select_listener.add(func)
216 |
217 | def has_select_listener(self, func):
218 | return self._on_select_listener.has_handler(func)
219 |
220 | def remove_select_listener(self, func):
221 | self._on_select_listener.remove(func)
222 |
223 | def add_reset_listener(self, func):
224 | self._on_reset_listener.add(func)
225 |
226 | def has_reset_listener(self, func):
227 | return self._on_reset_listener.has_handler(func)
228 |
229 | def remove_reset_listener(self, func):
230 | self._on_reset_listener.remove(func)
231 |
232 | def add_color_changed_listener(self, func):
233 | self._on_color_changed_listener.add(func)
234 |
235 | def has_color_changed_listener(self, func):
236 | return self._on_color_changed_listener.has_handler(func)
237 |
238 | def remove_color_changed_listener(self, func):
239 | self._on_color_changed_listener.remove(func)
240 |
241 | def _on_select(self, event):
242 | i, j = self.idea_indexes[event.ind[0]]
243 | event.selected_indexes = (i, j)
244 | self._on_select_listener.invoke(event)
245 |
246 | def _on_reset(self):
247 | self._on_reset_listener.invoke_empty()
248 |
249 | def _on_color_changed(self):
250 | self._on_color_changed_listener.invoke_empty()
251 |
252 | def _change_selected_color(self, eve):
253 |
254 | ind = self._get_point_index_from_event(eve)
255 |
256 | if self._prev_selected_ind == ind:
257 | return None
258 |
259 | if self._prev_selected_ind is not None:
260 | self.plot_data._edgecolors[self._prev_selected_ind] = self._point_colors[self._prev_selected_ind]
261 |
262 | self.plot_data._edgecolors[ind] = colors.to_rgba(self.selected_color)
263 | self._prev_selected_ind = ind
264 |
265 | self._mpl.redraw()
266 |
267 | def _annotate_selected(self, eve):
268 | ind = self._get_point_index_from_event(eve)
269 |
270 | if self._prev_annotation is not None:
271 | self._clear_selection()
272 |
273 | topic_1_name, topic_2_name = self.data.get_display_idea_names(self.idea_indexes[ind])
274 |
275 | x_cord, y_cord = self.x_values[ind], self.y_values[ind]
276 | text = "({0},{sep}{1})".format(topic_1_name, topic_2_name, sep=' ' if self.data._is_keywords else '\n')
277 |
278 | offset = self._get_text_offset(text) if x_cord > 0 else 0
279 |
280 | self._prev_annotation = self.axes.annotate(s=text, xy=(self.x_values[ind] - offset, self.y_values[ind]),
281 | annotation_clip=False)
282 | self._mpl.redraw()
283 |
284 | def _get_text_offset(self, text):
285 | text_width = self._get_text_width(text)
286 |
287 | dis_data_trans = self.axes.transData.inverted()
288 | disp_pnt_1 = (0, 0)
289 | disp_pnt_2 = (text_width, 0)
290 |
291 | data_pnt_1, data_pnt_2 = dis_data_trans.transform([disp_pnt_1, disp_pnt_2])
292 | return data_pnt_2[0] - data_pnt_1[0]
293 |
294 | def _get_text_width(self, text):
295 | t = self.axes.text(0, 0, text)
296 | bb = t.get_window_extent(renderer=self._mpl.figure.canvas.get_renderer())
297 | width = bb.width
298 | t.remove()
299 | return width
300 |
301 | def _get_point_index_from_event(self, eve):
302 | if hasattr(eve, "ind"):
303 | return eve.ind[0]
304 | elif hasattr(eve, "selected_indexes"):
305 | a, b = tuple(eve.selected_indexes)
306 | if (a, b) in self.idea_indexes:
307 | return self.idea_indexes.index((a, b))
308 | elif (b, a) in self.idea_indexes:
309 | return self.idea_indexes.index((b, a))
310 | else:
311 | logging.warn("Selected indexes, {0}, not found on PMI graph".format((a,b)))
312 | return None
313 |
314 | def _clear_selection(self):
315 | if self._prev_annotation is not None:
316 | self._prev_annotation.remove()
317 | self._prev_annotation = None
318 |
319 | def filter_relation(self, eve):
320 | idea_indexes = eve.selected_indexes
321 |
322 | self._clear_selection()
323 | self._clear_filter()
324 |
325 | self._add_filter([self.data.idea_names[index] for index in idea_indexes])
326 |
327 | old_point = None
328 | if self._prev_selected_ind is not None:
329 | old_point = self.idea_indexes[self._prev_selected_ind]
330 | # You want to plot everything in both the rows and columns specified by idea_indexes
331 | # Take two passes over the matrixes
332 | points = set()
333 | for i in idea_indexes: # Row
334 | for j in range(i + 1, self.data.num_ideas): # Col
335 | points.add((i, j))
336 |
337 | for j in idea_indexes:
338 | for i in range(0, j):
339 | points.add((i, j))
340 |
341 | self._plot(list(points))
342 |
343 | if old_point is not None:
344 | self._prev_selected_ind = None
345 | if old_point in self.idea_indexes:
346 | new_index = self.idea_indexes.index(old_point)
347 | self._on_select(type('', (object,), {"ind": [new_index]})())
348 |
349 | if hasattr(eve, "should_select") and eve.should_select:
350 | self._on_select_listener.invoke(eve)
351 |
352 | self._mpl.redraw()
353 |
354 | def _reset_graph(self):
355 | self._clear_selection()
356 | self.plot(sample=self.sample_size)
357 | self._clear_filter()
358 | self._mpl.redraw()
359 |
360 | def get_colors_hex(self):
361 | return ["#{:02x}{:02x}{:02x}".format(*rgb) for rgb in self._colors]
362 |
363 | def get_colors_rgb(self):
364 | return self._colors
365 |
366 | def _add_filter(self, names):
367 | self._control_panel_ui.filteredList.addItems(names)
368 |
369 | def _clear_filter(self):
370 | self._control_panel_ui.filteredList.clear()
371 |
372 |
373 | def get_row_col(n, i):
374 | """
375 | Given the index of a data point of an nxn strictly upper triangular matrix (a_ij = 0 for i>=j),
376 | this will calculate the row and column indexes in the nxn matrix
377 | """
378 | row = n - 2 - math.floor(math.sqrt(-8 * i + 4 * n * (n - 1) - 7) / 2 - 0.5)
379 | col = i + row + 1 - n * (n - 1) / 2 + (n - row) * ((n - row) - 1) / 2
380 | return int(row), int(col)
381 |
--------------------------------------------------------------------------------
/Visualizer/frames/QtMatplotlib.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 8/2/2017
3 |
4 | import sys
5 |
6 | import matplotlib
7 |
8 | import PyQt5.QtCore as QtCore
9 | import PyQt5.QtWidgets as QtWidgets
10 |
11 | from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
12 | from matplotlib.figure import Figure
13 | import numpy as np
14 |
15 | matplotlib.use("Qt5Agg")
16 |
17 |
18 | class QMatplotlib(FigureCanvasQTAgg):
19 |
20 | def __init__(self, parent=None, width=5, height=4, dpi=100):
21 | self.figure = Figure(figsize=(width, height), dpi=dpi)
22 | self.axes = self.figure.add_subplot(111)
23 |
24 | self.get_initial()
25 |
26 | FigureCanvasQTAgg.__init__(self, self.figure)
27 | self.setParent(parent)
28 |
29 | FigureCanvasQTAgg.setSizePolicy(self, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
30 | FigureCanvasQTAgg.updateGeometry(self)
31 |
32 | def get_initial(self):
33 | t = np.arange(0.0, 3.0, 0.01)
34 | s = np.sin(2*np.pi*t)
35 | self.axes.plot(t, s, 'r')
36 |
37 |
38 | class Application(QtWidgets.QMainWindow):
39 |
40 | def __init__(self):
41 | QtWidgets.QMainWindow.__init__(self)
42 |
43 | self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
44 |
45 | self.main_widget = QtWidgets.QWidget(self)
46 |
47 | layout = QtWidgets.QVBoxLayout(self.main_widget)
48 | graph = QMatplotlib(parent=self.main_widget)
49 | layout.addWidget(graph)
50 |
51 | self.main_widget.setFocus()
52 | self.setCentralWidget(self.main_widget)
53 |
54 |
55 | def test():
56 | import sys
57 | import PyQt5.QtWidgets as QtWidgets
58 |
59 | """
60 | ZetCode PyQt4 tutorial
61 |
62 | In this example, we create a skeleton
63 | of a calculator using a QtGui.QGridLayout.
64 |
65 | author: Jan Bodnar
66 | website: zetcode.com
67 | last edited: July 2014
68 | """
69 |
70 | class Example(QtWidgets.QWidget):
71 |
72 | def __init__(self):
73 | super(Example, self).__init__()
74 |
75 | self.init_ui()
76 |
77 | def init_ui(self):
78 |
79 | grid = QtWidgets.QGridLayout()
80 | self.setLayout(grid)
81 |
82 | names = ['Cls', 'Bck', '', 'Close',
83 | '7', '8', '9', '/',
84 | '4', '5', '6', '*',
85 | '1', '2', '3', '-',
86 | '0', '.', '=', '+']
87 |
88 | positions = [(i, j) for i in range(5) for j in range(4)]
89 |
90 | for position, name in zip(positions, names):
91 |
92 | if name == '':
93 | continue
94 | button = QtWidgets.QPushButton(name)
95 | grid.addWidget(button, *position)
96 |
97 | self.move(300, 150)
98 | self.setWindowTitle('Calculator')
99 | self.show()
100 |
101 | def main():
102 | app = QtWidgets.QApplication(sys.argv)
103 | ex = Example()
104 | sys.exit(app.exec_())
105 |
106 | main()
107 |
108 | if __name__ == "__main__":
109 | qApp = QtWidgets.QApplication(sys.argv)
110 | window = Application()
111 |
112 | window.show()
113 | sys.exit(qApp.exec_())
114 | # test()
115 |
--------------------------------------------------------------------------------
/Visualizer/frames/RelationTypeFrame.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 7/6/2017
3 |
4 | import PyQt5.QtWidgets as QtWidgets
5 | import PyQt5.QtGui as QtGui
6 |
7 | import numpy as np
8 |
9 | from events import listener, event
10 | from frames.VisualizerFrame import VisualizerFrame
11 | from ui import relation_types_tabs
12 |
13 |
14 | def _sort_by_strength(data, strength_index=2):
15 | sorted_list = sorted(data, key=lambda item: abs(item[strength_index]))
16 | sorted_list.reverse()
17 | return sorted_list
18 |
19 |
20 | class RelationTypeFrame(VisualizerFrame):
21 | def __init__(self, parent, data):
22 | super(RelationTypeFrame, self).__init__(parent=parent, data_manager=data)
23 |
24 | self.ui = relation_types_tabs.Ui_relationTypes()
25 | self.ui.setupUi(self)
26 |
27 | self.data = data
28 | self.types = self.data.relation_types
29 |
30 | self._buttons = []
31 | self._tables = []
32 | self._config_ui()
33 |
34 | self.list_data = {name: [] for name in self.types}
35 |
36 | self.active_index = None
37 | self._onselect_listener = listener.Listener()
38 |
39 | self._determine_relations()
40 | self._fill_tables()
41 |
42 | self._set_active_index(0)
43 |
44 | def _config_ui(self):
45 | for i, name in enumerate(self.types):
46 | tbl_name = "{0}Table".format(name.lower().replace('-', ''))
47 | tbl = self.findChild(QtWidgets.QTableWidget, tbl_name)
48 |
49 | tbl.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch)
50 |
51 | self._tables.append(tbl)
52 | tbl.itemSelectionChanged.connect(self._on_select)
53 |
54 | self.ui.tabWidget.currentChanged.connect(lambda i: self._set_active_index(i))
55 |
56 | def _determine_relations(self):
57 | pmi = self.data.pmi
58 | ts_correlation = self.data.ts_correlation
59 | trysts, friends, head, arms = [], [], [], []
60 | num_ideas = self.data.num_ideas
61 | cnt = 0
62 | for i in range(0, num_ideas):
63 | for j in range(i + 1, num_ideas):
64 | point_pmi = pmi[i, j]
65 | point_cor = ts_correlation[i, j]
66 | if np.isnan(point_pmi) or np.isnan(point_cor):
67 | continue
68 | if np.isinf(point_pmi) or np.isinf(point_cor):
69 | continue
70 | cnt += 1
71 | strength = point_pmi * point_cor
72 |
73 | if 0 <= point_pmi and point_cor < 0:
74 | trysts.append((i, j, strength))
75 | elif 0 <= point_pmi and 0 <= point_cor:
76 | friends.append((i, j, strength))
77 | elif point_pmi < 0 and point_cor < 0:
78 | head.append((i, j, strength))
79 | elif point_pmi < 0 and 0 <= point_cor:
80 | arms.append((i, j, strength))
81 |
82 | assert len(trysts) + len(friends) + len(head) + len(arms) == cnt
83 |
84 | self._add_to_list(friends, "Friends", sort=True, top=25)
85 | self._add_to_list(trysts, "Tryst", sort=True, top=25)
86 | self._add_to_list(head, "Head-To-Head", sort=True, top=25)
87 | self._add_to_list(arms, "Arms-Race", sort=True, top=25)
88 |
89 | def _add_to_list(self, items, name, sort=True, top=None):
90 | data = self.list_data[name]
91 | if sort:
92 | items = _sort_by_strength(items)
93 |
94 | if top is not None:
95 | items = items[:top]
96 |
97 | data.extend(items)
98 |
99 | def _fill_tables(self):
100 | for index, name in enumerate(self.data.relation_types):
101 | raw_data = self.list_data[name]
102 | tbl = self._tables[index]
103 |
104 | data = self._get_output_repr(raw_data)
105 |
106 | for i, relation in enumerate(data):
107 | tbl.insertRow(i)
108 | for j, item in enumerate(relation):
109 | qtbl_item = QtWidgets.QTableWidgetItem(item)
110 | tbl.setItem(i, j, qtbl_item)
111 |
112 | def _get_output_repr(self, items):
113 | outputs = []
114 | for item in items:
115 | output = ("{n:.{d}}".format(n=item[2], d=4), self.data.idea_names[item[0]], self.data.idea_names[item[1]])
116 | outputs.append(output)
117 | return outputs
118 |
119 | def clear_lists(self):
120 | for table in self._tables:
121 | table.clearContents()
122 |
123 | def add_select_listener(self, func):
124 | self._onselect_listener.add(func)
125 |
126 | def has_select_listener(self, func):
127 | return self._onselect_listener.has_handler(func)
128 |
129 | def remove_select_listener(self, func):
130 | self._onselect_listener.remove(func)
131 |
132 | def _on_select(self):
133 | col_count = self._tables[self.active_index].columnCount()
134 |
135 | selected_items = dict()
136 | for item in self._tables[self.active_index].selectedItems():
137 | row, col = item.row(), item.column()
138 | if row not in selected_items.keys():
139 | selected_items[row] = [0] * col_count
140 | selected_items[row][col] = item.text()
141 |
142 | if not len(selected_items):
143 | return None
144 |
145 | selected_indexes = list()
146 | for row, item in selected_items.items():
147 | selected_indexes.append(self.data.idea_numbers[item[1]])
148 | selected_indexes.append(self.data.idea_numbers[item[2]])
149 |
150 | eve = event.Event()
151 | eve.selected_indexes = selected_indexes
152 | eve.should_select = True
153 | self._onselect_listener.invoke(eve)
154 |
155 | def _btn_click(self, name):
156 | self._set_active(name)
157 |
158 | def _set_active(self, name):
159 | index = self.types.index(name)
160 | return self._set_active_index(index)
161 |
162 | def _set_active_index(self, index):
163 | if self.active_index is not None:
164 | self._tables[self.active_index].clearSelection()
165 |
166 | self.active_index = index
167 |
168 | def clear_selection(self):
169 | self._tables[self.active_index].clearSelection()
170 |
171 | def color_tabs(self, color_map):
172 | tab_bar = self.ui.tabWidget.tabBar()
173 |
174 | for i, name in zip(range(tab_bar.count()), self.types):
175 | tab_bar.setTabTextColor(i, QtGui.QColor(*color_map[name]))
176 |
177 | def color_changed(self, pmi_frame):
178 | self.color_tabs(pmi_frame.color_samples)
179 |
--------------------------------------------------------------------------------
/Visualizer/frames/TimeSeriesFrame.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 7/5/2017
3 |
4 | import numpy as np
5 | import PyQt5.QtWidgets as QtWidgets
6 |
7 | from frames.VisualizerFrame import VisualizerFrame
8 | from frames.MatplotlibFrame import QMatplotlib
9 | from frames.matplotlib_util import Utils
10 |
11 |
12 | import matplotlib.patches as mpatches
13 |
14 |
15 | class TimeSeriesFrame(VisualizerFrame, Utils):
16 | def __init__(self, parent, data):
17 | super(TimeSeriesFrame, self).__init__(parent=parent, data_manager=data)
18 |
19 | self.layout = QtWidgets.QVBoxLayout(self)
20 |
21 | self._mpl = QMatplotlib(parent=self)
22 | self.axes = self._mpl.axes
23 |
24 | self.layout.addWidget(self._mpl)
25 |
26 | self.data = data
27 |
28 | self._init_plot()
29 |
30 | self.series = None
31 | self._has_data = False
32 |
33 | def _init_plot(self):
34 | self.axes.clear()
35 | self._has_data = False
36 | self.axes.set_title("Time Series")
37 | self.axes.set_xlabel("Year")
38 | self.axes.set_ylabel("Frequency")
39 | self.axes.set_ylim([0, 1])
40 |
41 | def plot_series(self, y, name=None, redraw=True):
42 | self._add_series(y)
43 | self.axes.plot(self.data.x_values, y)
44 | if name is not None:
45 | self.axes.legend([name], loc="best")
46 |
47 | if redraw:
48 | self.redraw()
49 |
50 | self._has_data = True
51 |
52 | def plot_idea_indexes_event(self, event):
53 | self.plot_idea_indexes(event.selected_indexes)
54 |
55 | def plot_idea_indexes(self, indexes, names=None):
56 | self.clear()
57 |
58 | index_names = []
59 | for index in indexes:
60 | self.plot_series(self.data.ts_matrix[index], redraw=False)
61 | index_names.append(self.data.get_display_idea_names(index))
62 |
63 | # self.get_correlation()
64 |
65 | if names is not None:
66 | self.axes.legend(names, loc="best")
67 | else:
68 | self.axes.legend(index_names, loc="best")
69 |
70 | self._mpl.redraw()
71 |
72 | def _add_series(self, data):
73 | if self.series is None:
74 | self.series = np.copy(data)
75 | else:
76 | self.series = np.column_stack((self.series, data))
77 |
78 | def get_correlation(self):
79 | correlation = np.corrcoef(self.series, rowvar=False)
80 | self._correlation_data.set(round(correlation[0, 1], 5))
81 |
82 | def clear(self):
83 | self.series = None
84 | self._init_plot()
85 | self._mpl.redraw()
86 |
87 | # self._correlation_data.set(0)
88 |
89 | def select_relation_type(self, event):
90 | self.plot_idea_indexes(event.selected_indexes)
91 |
--------------------------------------------------------------------------------
/Visualizer/frames/TimeSeriesVisualizer.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 7/11/17
3 |
4 | import matplotlib.pyplot as plt
5 |
6 |
7 | # Plot the Time Series for the given idea
8 | def plot_idea_timeseries(idea_name, idea_numbers, ts_matrix):
9 | ts_data = ts_matrix[idea_numbers[idea_name]]
10 |
11 | start = 1980
12 | end = 2015
13 |
14 | plt.plot(ts_data)
15 | plt.show()
16 |
17 |
18 | def show_time_series(idea_numbers, ts_matrix):
19 | # Get a list of idea names
20 | ideas = list(idea_numbers.keys())
21 |
22 | display_help()
23 |
24 | quit = False
25 | while not quit:
26 | selection = input(">")
27 | if selection in ideas:
28 | plot_idea_timeseries(selection, idea_numbers, ts_matrix)
29 | elif selection == "l":
30 | print(ideas)
31 | elif selection == "q":
32 | quit = True
33 | else:
34 | display_help()
35 |
36 |
37 | def display_help():
38 | print("Enter an idea name to view the time series, l to list ideas, q to quit, or h to view this help message")
39 |
--------------------------------------------------------------------------------
/Visualizer/frames/TopRelations.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 7/10/2017
3 |
4 | import PyQt5.QtWidgets as QtWidgets
5 |
6 | import numpy as np
7 |
8 | from events import event, listener
9 | from frames.VisualizerFrame import VisualizerFrame
10 | from ui import top_relations
11 |
12 |
13 | class TopRelations(VisualizerFrame):
14 | def __init__(self, parent, data, topic_index=0):
15 | super(TopRelations, self).__init__(parent, data_manager=data)
16 |
17 | self.ui = top_relations.Ui_topRelation()
18 | self.ui.setupUi(self)
19 |
20 | self._index = topic_index
21 |
22 | self.ui.tableWidget.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch)
23 |
24 | self._onselect_listener = listener.Listener()
25 | self.ui.tableWidget.itemClicked.connect(self._on_select)
26 |
27 | self.idea_index = -1
28 |
29 | def set_idea_name(self, name):
30 | return self.set_idea_index(self.data.idea_numbers[name])
31 |
32 | def set_idea_index(self, index):
33 | strengths = []
34 | pmi, ts_cor = self.data.pmi, self.data.ts_correlation
35 | for i in range(0, self.data.num_ideas):
36 | for j in range(i + 1, self.data.num_ideas):
37 | if i != index and j != index:
38 | continue
39 | point_pmi = pmi[i, j]
40 | point_cor = ts_cor[i, j]
41 | if np.isnan(point_pmi) or np.isnan(point_cor):
42 | continue
43 | if np.isinf(point_pmi) or np.isinf(point_cor):
44 | continue
45 |
46 | strength = point_pmi * point_cor
47 | point_type = self._get_point_type(point_pmi, point_cor)
48 |
49 | other_topic_name = self.data.idea_names[i if i != index else j]
50 | self._insert_sorted(strengths, ("{n:.{d}}".format(n=strength, d=3), point_type, other_topic_name),
51 | sort_index=0)
52 |
53 | self._clear_list()
54 | self._insert_list(strengths)
55 |
56 | self.idea_index = index
57 |
58 | # Update the frame title
59 | self.ui.relationName.setText(self.data.get_display_idea_names(index))
60 |
61 | @staticmethod
62 | def _get_point_type(point_pmi, point_cor):
63 | if 0 <= point_pmi and point_cor < 0:
64 | return "Tryst"
65 | elif 0 <= point_pmi and 0 <= point_cor:
66 | return "Friends"
67 | elif point_pmi < 0 and point_cor < 0:
68 | return "Head-To-Head"
69 | elif point_pmi < 0 and 0 <= point_cor:
70 | return "Arms-Race"
71 |
72 | @staticmethod
73 | def _insert_sorted(items, item, sort_index=0):
74 | index = 0
75 | for index in range(len(items)):
76 | list_item = items[index]
77 |
78 | if item[sort_index] >= list_item[sort_index]:
79 | break
80 | items.insert(index, item)
81 |
82 | def _insert_list(self, items):
83 | tbl = self.ui.tableWidget
84 | for i, relation in enumerate(items):
85 | tbl.insertRow(i)
86 | for j, item in enumerate(relation):
87 | qtbl_item = QtWidgets.QTableWidgetItem(item)
88 | tbl.setItem(i, j, qtbl_item)
89 |
90 | def set_idea_event(self, event):
91 | self.set_idea_index(event.selected_indexes[self._index])
92 |
93 | def clear(self):
94 | self.ui.relationName.clear()
95 | self._clear_list()
96 |
97 | def _clear_list(self):
98 | self.ui.tableWidget.clearContents()
99 |
100 | def clear_selection(self):
101 | self.ui.tableWidget.clearSelection()
102 |
103 | def _on_select(self):
104 | selected = self.data.idea_numbers[self.ui.tableWidget.selectedItems()[-1].text()]
105 | eve = event.Event()
106 | eve.selected_indexes = [self.idea_index, selected]
107 | self._onselect_listener.invoke(eve)
108 |
109 | def add_select_listener(self, func):
110 | self._onselect_listener.add(func)
111 |
112 | def has_select_listener(self, func):
113 | return self._onselect_listener.has_handler(func)
114 |
115 | def remove_select_listener(self, func):
116 | self._onselect_listener.remove(func)
117 |
--------------------------------------------------------------------------------
/Visualizer/frames/VisualizerFrame.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 7/2/2017
3 |
4 | import PyQt5.QtWidgets as QtWidgets
5 |
6 |
7 | class VisualizerFrame(QtWidgets.QWidget):
8 | """Abstract class, please don't instantiate"""
9 | def __init__(self, parent=None, data_manager=None):
10 | super(VisualizerFrame, self).__init__(parent)
11 | self.data = data_manager
12 |
--------------------------------------------------------------------------------
/Visualizer/frames/VisualizerWidget.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 8/7/2017
3 |
4 | import logging
5 |
6 | from PyQt5.QtWidgets import QWidget, QHBoxLayout, QTabWidget, QSplitter, QFileDialog
7 |
8 | from events.listener import Listener
9 | from frames.VisualizerFrame import VisualizerFrame
10 | from frames.PMIPlot import PMIPlot
11 | from frames.TimeSeriesFrame import TimeSeriesFrame
12 | from frames.ListFrame import ListFrame
13 | from frames.RelationTypeFrame import RelationTypeFrame
14 | from frames.TopRelations import TopRelations
15 | from ui import visualizer
16 |
17 | import data
18 |
19 |
20 | class VisualizerWidget(VisualizerFrame):
21 | def __init__(self, parent, data_manager):
22 | super(VisualizerWidget, self).__init__(parent=parent)
23 |
24 | self.ui = visualizer.Ui_visualizaerWidget()
25 | self.ui.setupUi(self)
26 |
27 | self._data = data_manager
28 | self._load_visualizer()
29 |
30 | self._reset_listener = Listener()
31 |
32 | def sizeHint(self):
33 | return self.parent().size()
34 |
35 | def _load_visualizer(self):
36 | self._pmi = PMIPlot(self, self._data)
37 | self._pmi.plot(sample=1000)
38 | self.ui.pmiWidget.layout().addWidget(self._pmi)
39 |
40 | self._ts = TimeSeriesFrame(self, self._data)
41 | self.ui.tsWidget.layout().addWidget(self._ts)
42 |
43 | self._idea_list = ListFrame(self.ui.tabWidget, data=self._data)
44 | self.ui.tabWidget.insertTab(0, self._idea_list, "Ideas")
45 |
46 | self._relation_types = RelationTypeFrame(self, data=self._data)
47 | self.ui.tabWidget.insertTab(1, self._relation_types, "Types")
48 | self._relation_types.color_tabs(self._pmi.color_samples)
49 |
50 | self._top_relation_1 = TopRelations(self, data=self._data, topic_index=0)
51 | self.ui.tabWidget.insertTab(2, self._top_relation_1, "Top Relation 1")
52 | self._top_relation_2 = TopRelations(self, data=self._data, topic_index=1)
53 | self.ui.tabWidget.insertTab(3, self._top_relation_2, "Top Relation 2")
54 |
55 | # PMI Select Listener
56 | self._pmi.add_select_listener(self._ts.plot_idea_indexes_event)
57 | self._pmi.add_select_listener(self._top_relation_1.set_idea_event)
58 | self._pmi.add_select_listener(self._top_relation_2.set_idea_event)
59 |
60 | # Idea list Select Listener
61 | self._idea_list.add_select_listener(self._pmi.filter_relation)
62 |
63 | # Relation types Select Listener
64 | self._relation_types.add_select_listener(self._pmi.filter_relation)
65 |
66 | # PMI reset Listeners
67 | self._pmi.add_reset_listener(self._clear_list_selections_factory())
68 | self._pmi.add_reset_listener(self._ts.clear)
69 |
70 | # Keep lists current with selection
71 | self._relation_types.add_select_listener(self._pmi.filter_relation)
72 |
73 | # Clear other lists on selection
74 | self._relation_types.add_select_listener(self._clear_list_selections_factory(self._relation_types))
75 | self._idea_list.add_select_listener(self._clear_list_selections_factory(self._idea_list))
76 | self._top_relation_1.add_select_listener(self._clear_list_selections_factory(self._top_relation_1))
77 | self._top_relation_2.add_select_listener(self._clear_list_selections_factory(self._top_relation_2))
78 |
79 | # Auxillary data structures
80 | self._lists = {self._idea_list, self._relation_types, self._top_relation_1, self._top_relation_2}
81 |
82 | def resizeEvent(self, event):
83 | dpi = self.physicalDpiX()
84 | # Make the width of the screen 4 inches or one fifth the width of the screen
85 | self.ui.tabWidget.setFixedWidth(min(4*dpi, int(self.size().width()/5)))
86 | super(VisualizerWidget, self).resizeEvent(event)
87 |
88 | def _clear_list_selections_factory(self, caller=None):
89 | def func():
90 | for item in self._lists:
91 | if item == caller:
92 | continue
93 | item.clear_selection()
94 | return func
95 |
96 | def save_pmi(self):
97 | self._save_plot(self._pmi, "PMI")
98 |
99 | def save_ts(self):
100 | self._save_plot(self._ts, "Time Series")
101 |
102 | def save_both(self):
103 | self._save_plot(self._pmi, "PMI")
104 | self._save_plot(self._ts, "Time Series")
105 |
106 | def save_data(self, fname):
107 | return data.save_data(fname, self._data)
108 |
109 | def _save_plot(self, target, plot_name):
110 | if not target.confirm_on_empty(plot_name):
111 | return None
112 |
113 | dialog = QFileDialog(self)
114 | dialog.setAcceptMode(QFileDialog.AcceptSave)
115 | dialog.setFileMode(QFileDialog.AnyFile)
116 | formats = self._mpl_output_formats(self._pmi)
117 | dialog.setNameFilters(["Matplotlib Formats " + formats, "All Files (*)"])
118 | if dialog.exec():
119 | target.save_plot(dialog.selectedFiles()[0])
120 |
121 | @staticmethod
122 | def _mpl_output_formats(widget):
123 | items = []
124 | for key in widget.get_supported_formats():
125 | items.append("*.{0}".format(key))
126 | return '(' + ', '.join(items) + ')'
127 |
--------------------------------------------------------------------------------
/Visualizer/frames/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nwrush/Visualization/bc134aa02156956ea3644b34d491da9f0e9f63ae/Visualizer/frames/__init__.py
--------------------------------------------------------------------------------
/Visualizer/frames/matplotlib_util.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 8/18/17
3 |
4 | from PyQt5.QtWidgets import QMessageBox
5 |
6 |
7 | class Utils:
8 | def save_plot(self, fname):
9 | self._mpl.get_figure().savefig(fname)
10 |
11 | def confirm_on_empty(self, name):
12 | if not self._has_data:
13 | reply = QMessageBox.question(self, "Confirm Save Plot",
14 | "{0} plot is empty\nAre you sure you want to save it?".format(name),
15 | QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
16 | return int(reply) == QMessageBox.Yes
17 | return True
18 |
19 | def get_supported_formats(self):
20 | return self._mpl.canvas.get_supported_filetypes()
21 |
--------------------------------------------------------------------------------
/Visualizer/frames/preprocessor_controller.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 7/18/17
3 |
4 | import logging
5 | import os
6 | import os.path
7 | import queue
8 | import shutil
9 | import threading
10 | import sys
11 |
12 | from PyQt5.QtCore import QTimer
13 | from PyQt5.QtWidgets import QFileDialog, QVBoxLayout, QWidget, QMessageBox
14 | from PyQt5.QtGui import QPalette, QColor
15 |
16 | from frames.VisualizerFrame import VisualizerFrame
17 | from ui import preprocessor_form
18 | from ui import preprocessor_run
19 |
20 | has_preprocessor = False
21 | try:
22 | from idea_relations import main as idea_rel_main
23 | has_preprocessor = True
24 | except ImportError as ex:
25 | logging.error("Module idea_relations not found, preprocessor will not run.")
26 | logging.exception(ex)
27 | idea_rel_main = None
28 |
29 |
30 | RUNTYPE_OPTIONS = ["Keywords", "Topics"]
31 | GROUP_BY = ["Year", "Month", "Quarter"]
32 |
33 | DEFAULT_PALETTE = QPalette()
34 |
35 | DEFAULT_PROC_DIR = "./output/{exp_name}/proc/"
36 | DEFAULT_FINAL_DIR = "./output/{exp_name}/final/"
37 |
38 |
39 | def import_preprocessor():
40 | has_preprocessor = False
41 | try:
42 | from idea_relations import main as idea_rel_main
43 | has_preprocessor = True
44 | except ImportError as ex:
45 | logging.error("Module idea_relations not found, preprocessor will not run.")
46 | logging.exception(ex)
47 | idea_rel_main = None
48 | return has_preprocessor, idea_rel_main
49 |
50 |
51 | class PreprocessorController(VisualizerFrame):
52 | def __init__(self, parent, finished_callback=None):
53 | super(PreprocessorController, self).__init__(parent=parent)
54 |
55 | self._layout = QVBoxLayout(self)
56 | self.setLayout(self._layout)
57 |
58 | self._form_widget = QWidget(self)
59 | self._form_ui = preprocessor_form.Ui_preprocessorForm()
60 | self._form_ui.setupUi(self._form_widget)
61 | self._layout.addWidget(self._form_widget)
62 | self._connect_form_ui()
63 |
64 | self._run_widget = QWidget(self)
65 | self._run_ui = preprocessor_run.Ui_preprocessorRun()
66 | self._run_ui.setupUi(self._run_widget)
67 | self._layout.addWidget(self._run_widget)
68 | self._connect_run_ui()
69 |
70 | self._timer = QTimer()
71 | self._timer.setSingleShot(True)
72 | self._timer.setInterval(500)
73 |
74 | self._preprocessor_thread = None
75 | self._num_steps = None
76 | self._message_queue = queue.Queue()
77 | self._callback = finished_callback
78 |
79 | self.output_name = None
80 |
81 | if not has_preprocessor:
82 | QMessageBox.about(self, "Missing Preprocessor",
83 | "The preprocessor could not be loaded and therefore can't be run\n"
84 | "Check the log file for details")
85 |
86 | def _connect_form_ui(self):
87 | # Setup the option combo box
88 | ui = self._form_ui
89 | ui.optionBox.currentIndexChanged.connect(self._option_box_changed)
90 | self._option_box_changed(0)
91 |
92 | self._file_dialog_factory(ui.inputFileBtn, ui.inputFile, QFileDialog.ExistingFile)
93 | self._file_dialog_factory(ui.outputDirBtn, ui.outputDir, QFileDialog.Directory)
94 | self._file_dialog_factory(ui.finalDirBtn, ui.finalDir, QFileDialog.Directory)
95 | self._file_dialog_factory(ui.bckFileBtn, ui.bckFile, QFileDialog.ExistingFile)
96 | self._file_dialog_factory(ui.malletDirBtn, ui.malletDir, QFileDialog.Directory)
97 |
98 | ui.showAdvancedBox.clicked.connect(self._toggle_advanced)
99 | self._toggle_advanced(ui.showAdvancedBox.isChecked())
100 |
101 | def _option_box_changed(self, index):
102 | text = self._form_ui.optionBox.currentText()
103 |
104 | is_keywords = text.lower() == "keywords"
105 |
106 | self._form_ui.bckFile.setEnabled(is_keywords)
107 | self._form_ui.bckFileBtn.setEnabled(is_keywords)
108 |
109 | self._form_ui.malletDir.setEnabled(not is_keywords)
110 | self._form_ui.malletDirBtn.setEnabled(not is_keywords)
111 |
112 | @staticmethod
113 | def _file_dialog_factory(btn, line, selection_type):
114 | def tmp():
115 | dialog = QFileDialog()
116 | dialog.setFileMode(selection_type)
117 |
118 | dialog.exec()
119 | selected_list = dialog.selectedFiles()
120 | if selected_list:
121 | line.setText(selected_list[0])
122 |
123 | btn.clicked.connect(tmp)
124 |
125 | def _toggle_advanced(self, checked):
126 | ui = self._form_ui
127 | if checked:
128 | ui.outputDir.show()
129 | ui.outputDirLbl.show()
130 | ui.outputDirBtn.show()
131 |
132 | ui.finalDir.show()
133 | ui.finalDirLbl.show()
134 | ui.finalDirBtn.show()
135 | else:
136 | ui.outputDir.hide()
137 | ui.outputDirLbl.hide()
138 | ui.outputDirBtn.hide()
139 |
140 | ui.finalDir.hide()
141 | ui.finalDirLbl.hide()
142 | ui.finalDirBtn.hide()
143 |
144 | def _get_form_values(self):
145 | ui = self._form_ui
146 |
147 | args = dict()
148 |
149 | args["option"] = ui.optionBox.currentText().lower()
150 | args["input_file"] = ui.inputFile.text()
151 | args["mallet_bin_dir"] = ui.malletDir.text()
152 | args["background_file"] = ui.bckFile.text()
153 | args["group_by"] = ui.groupBox.currentText().lower()
154 | args["prefix"] = ui.prefix.text()
155 | args["num_ideas"] = ui.numIdeas.text()
156 |
157 | args["tokenize"] = ui.tokenizeBox.isChecked()
158 | args["lemmatize"] = ui.lemmatizeBox.isChecked()
159 | args["nostopwords"] = ui.stopwordBox.isChecked()
160 |
161 | output_dir_text = ui.outputDir.text()
162 | if not output_dir_text.strip():
163 | args["data_output_dir"] = DEFAULT_PROC_DIR.format(exp_name=args["prefix"])
164 | else:
165 | args["data_output_dir"] = output_dir_text
166 |
167 | final_dir_text = ui.finalDir.text()
168 | if not final_dir_text.strip():
169 | args["final_output_dir"] = DEFAULT_FINAL_DIR.format(exp_name=args["prefix"])
170 | else:
171 | args["final_output_dir"] = final_dir_text
172 |
173 | return args
174 |
175 | def _connect_run_ui(self):
176 | ui = self._run_ui
177 | ui.progressBar.hide()
178 | ui.progressBar.setMinimum(0)
179 | ui.progressBar.setMaximum(0)
180 |
181 | ui.runPreprocessor.clicked.connect(self._run_preprocessor)
182 | ui.runPreprocessor.setEnabled(has_preprocessor)
183 |
184 | def _start(self):
185 | valid = self._validate_params(None)
186 | if not valid:
187 | return
188 |
189 | self._run_preprocessor()
190 |
191 | def _validate_params(self, args):
192 | valid = True
193 |
194 | ui = self._form_ui
195 |
196 | invalid_palette = QPalette()
197 | invalid_palette.setColor(QPalette.Active, QPalette.Base, QColor("red"))
198 |
199 | if not os.path.isfile(args["input_file"]):
200 | valid = False
201 | ui.inputFile.setPalette(invalid_palette)
202 | self._set_text_changed_signal(ui.inputFile)
203 |
204 | is_keywords = args["option"] == "keywords"
205 |
206 | if is_keywords and not os.path.isfile(args["background_file"]):
207 | valid = False
208 | ui.bckFile.setPalette(invalid_palette)
209 | self._set_text_changed_signal(ui.bckFile)
210 |
211 | if not is_keywords and not os.path.isdir(args["mallet_bin_dir"]):
212 | valid = False
213 | ui.malletDir.setPalette(invalid_palette)
214 | self._set_text_changed_signal(ui.malletDir)
215 |
216 | if not args["prefix"].strip():
217 | valid = False
218 | ui.prefix.setPalette(invalid_palette)
219 | self._set_text_changed_signal(ui.prefix)
220 |
221 | try:
222 | int(args["num_ideas"])
223 | except ValueError:
224 | valid = False
225 | ui.numIdeas.setPalette(invalid_palette)
226 | self._set_text_changed_signal(ui.numIdeas)
227 |
228 | if is_keywords:
229 | data_path = os.path.join("idea_relations", args["data_output_dir"])
230 | final_path = os.path.join("idea_relations", args["final_output_dir"])
231 |
232 | if os.path.isdir(data_path):
233 | self._warn_existing_output_dir(data_path)
234 |
235 | if os.path.isdir(final_path):
236 | self._warn_existing_output_dir(final_path)
237 |
238 | return valid
239 |
240 | @staticmethod
241 | def _set_text_changed_signal(field):
242 | def unset_connection():
243 | field.setPalette(DEFAULT_PALETTE)
244 | field.textEdited.disconnect(unset_connection)
245 |
246 | field.textChanged.connect(unset_connection)
247 |
248 | def _warn_existing_output_dir(self, path):
249 | path = os.path.abspath(path)
250 | reply = QMessageBox.question(self, "Reuse previous data",
251 | "Intermediate files were found at\n{0}\nDo you want to reuse them?".format(path),
252 | QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
253 | reuse = int(reply) == QMessageBox.Yes
254 | if not reuse:
255 | shutil.rmtree(path)
256 |
257 | def _run_preprocessor(self):
258 | values = self._get_form_values()
259 | if not self._validate_params(values):
260 | return
261 |
262 | args = list()
263 | for name, value in values.items():
264 | if value:
265 | args.append("--" + name)
266 | if isinstance(value, str):
267 | args.append(value)
268 |
269 | args.append("--no_create_graphs")
270 |
271 | output_name = "banana.p"
272 | args.extend(["--objects_location", output_name])
273 |
274 | if os.name == 'nt':
275 | # args = ["python.exe", "-u", "main.py"] + args
276 | # args = ["python.exe", "--version"]
277 | pass
278 | else:
279 | # args = ["python", "--version"]
280 | # args = ["python", "-u", "main.py"] + args
281 | pass
282 |
283 | # has_preprocessor, idea_rel_main = import_preprocessor()
284 |
285 | if has_preprocessor:
286 | logging.info("Starting preprocessor")
287 | self._preprocessor_thread = threading.Thread(target=self._preprocessor_thread_runner,
288 | args=(args, idea_rel_main.main))
289 |
290 | self._run_ui.progressBar.show()
291 | self._preprocessor_thread.start()
292 |
293 | self._timer.timeout.connect(self._poll_queue)
294 | self._timer.start()
295 |
296 | self.output_name = output_name
297 | else:
298 | logging.info("Preprocessor was not found on import and won't be run.")
299 |
300 | def _preprocessor_thread_runner(self, args, func):
301 | try:
302 | func(args, self._message_queue)
303 | self._message_queue.put(0)
304 |
305 | except Exception as ex:
306 | logging.error("Exception occurred while running the preprocessor")
307 | logging.exception(ex)
308 | self._message_queue.put(-666)
309 | raise ex
310 |
311 | def _poll_queue(self):
312 | if not self._message_queue.empty():
313 | msg = self._message_queue.get()
314 | if isinstance(msg, int):
315 | code = msg
316 | else:
317 | code = int(msg.split(':')[1])
318 | if code <= 0:
319 | self._preprocessor_done(-1 * code)
320 | return
321 |
322 | if self._num_steps is None:
323 | self._num_steps = code
324 | self._run_ui.progressBar.setRange(0, code)
325 | self._run_ui.progressBar.setValue(0)
326 | else:
327 | self._run_ui.progressBar.setValue(code)
328 |
329 | self._timer.start()
330 | else:
331 | self._timer.start()
332 |
333 | def _preprocessor_done(self, rtn_code):
334 | self._run_ui.progressBar.setRange(0, 1)
335 | self._run_ui.progressBar.setValue(0)
336 |
337 | self._num_steps = None
338 |
339 | if rtn_code != 666:
340 | self._run_ui.progressBar.setValue(1)
341 |
342 | if self._callback is not None:
343 | self._callback(rtn_code)
344 | logging.info("Finished preprocessor run with code {0}".format(rtn_code))
345 |
346 | def kill(self):
347 | if self._preprocessor_thread is not None:
348 | logging.info("Killing preprocessor thread")
349 | self._preprocessor_thread.kill()
350 |
--------------------------------------------------------------------------------
/Visualizer/main.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 8/28/2017
3 |
4 | import sys
5 |
6 | import Visualizer
7 |
8 | if __name__ == '__main__':
9 | Visualizer.main()
10 |
--------------------------------------------------------------------------------
/Visualizer/menu.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 7/22/17
3 |
4 | import tkinter as tk
5 | import tkinter.filedialog as filedialog
6 |
7 | from menus import pmi_menu
8 |
9 | class Menubar(tk.Menu):
10 |
11 | def __init__(self, root, data):
12 | super(Menubar, self).__init__(master=root)
13 |
14 | self._data = data
15 |
16 | self.filemenu = tk.Menu(master=self, tearoff=0)
17 | self.filemenu.add_command(label="Open", command=self.open)
18 |
19 | self.editmenu = tk.Menu(master=self, tearoff=0)
20 | self.editmenu.add_command(label="Edit PMI", command=self.edit_pmi)
21 |
22 | self.add_cascade(label="File", menu=self.filemenu)
23 | self.add_cascade(label="Edit", menu=self.editmenu)
24 |
25 | self._open_handlers = set()
26 |
27 | def hello(self):
28 | print("hello")
29 |
30 | def open(self):
31 | value = filedialog.askopenfilename(parent=self)
32 | for func in self._open_handlers:
33 | func(value)
34 |
35 | def edit_pmi(self):
36 | pmi_menu.PMIMenu(self, self._data)
37 |
--------------------------------------------------------------------------------
/Visualizer/menus/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nwrush/Visualization/bc134aa02156956ea3644b34d491da9f0e9f63ae/Visualizer/menus/__init__.py
--------------------------------------------------------------------------------
/Visualizer/menus/pmi_menu.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 7/25/2017
3 |
4 | import tkinter as tk
5 | import tkinter.colorchooser
6 | import tkinter.ttk as ttk
7 |
8 | def rgb_to_luma(r, g, b):
9 | luminance = 0.2126*r + 0.7152*g + 0.0722*b
10 |
11 | def create(parent):
12 | return PMIMenu(parent)
13 |
14 | def create_factory(parent):
15 | def func():
16 | create(parent)
17 | return func
18 |
19 | class PMIMenu(object):
20 |
21 | def __init__(self, parent):
22 | self._window = tk.Toplevel(master=parent.frame)
23 | self._window.title("PMI Graph Settings")
24 |
25 | self._parent = parent
26 | self._data = parent.data
27 |
28 | self._color_settings = ttk.LabelFrame(master=self._window, text="Colors")
29 | self._color_settings.pack()
30 |
31 | self._colors = []
32 | for index, relation in enumerate(self._data.relation_types):
33 | label = tk.Label(master=self._color_settings, text="{0} Color".format(relation))
34 | btn = tk.Button(master=self._color_settings, text="Get Color", command=self._get_color_button(index))
35 | label.grid(row=index, column=0, sticky="we")
36 | btn.grid(row=index, column=1)
37 |
38 | parent_color = self._parent._colors[index]
39 | self._colors.append([label, btn, parent_color]) # Use a better default here
40 |
41 | self._window.protocol("WM_DELETE_WINDOW", self.on_exit)
42 |
43 | def _get_color_button(self, index):
44 | def func():
45 | rgb, hex = tk.colorchooser.askcolor(parent=self._window)
46 | self._window.lift()
47 |
48 | self._colors[index][2] = rgb
49 |
50 | sample = self._colors[index][0]
51 | sample.config(background=hex)
52 |
53 | r, g, b = rgb
54 | # https://en.wikipedia.org/wiki/Relative_luminance
55 | # ITU-R BT.709 Primaries
56 | luma = (0.2126*r + 0.7152*g + 0.0722*b)/255
57 | if luma >= 0.5:
58 | sample.config(fg="Black")
59 | else:
60 | sample.config(fg="White")
61 |
62 | return func
63 |
64 | def on_exit(self):
65 | new_colors = []
66 | for index, color in enumerate(self._colors):
67 | _, _, rgb = color
68 |
69 | new_colors.append(rgb)
70 |
71 | self._window.destroy()
72 | self._parent._update_colors(new_colors)
73 |
--------------------------------------------------------------------------------
/Visualizer/models/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nwrush/Visualization/bc134aa02156956ea3644b34d491da9f0e9f63ae/Visualizer/models/__init__.py
--------------------------------------------------------------------------------
/Visualizer/models/list_model.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 9/5/2017
3 |
4 | import PyQt5.QtCore as QtCore
5 | from PyQt5.QtCore import Qt
6 |
7 |
8 | class ListModel(QtCore.QAbstractListModel):
9 |
10 | def __init__(self, data, parent=None):
11 | super(ListModel, self).__init__(parent)
12 |
13 | self._data = sorted(list(data))
14 |
15 | def rowCount(self, parent=None, *args, **kwargs):
16 | return len(self._data)
17 |
18 | def data(self, index, role=None):
19 | if role == Qt.DisplayRole:
20 | return self._data[index.row()]
21 | return QtCore.QVariant() # Return an invalid variant
22 |
23 |
24 | class ListModelFilter(QtCore.QSortFilterProxyModel):
25 |
26 | def __init__(self, parent=None):
27 | super(ListModelFilter, self).__init__(parent)
28 |
--------------------------------------------------------------------------------
/Visualizer/pmi_corr_plot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nwrush/Visualization/bc134aa02156956ea3644b34d491da9f0e9f63ae/Visualizer/pmi_corr_plot.png
--------------------------------------------------------------------------------
/Visualizer/qt_test.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 8/1/2017
3 |
4 | import sys
5 |
6 | import PyQt5.QtWidgets as QtWidgets
7 |
8 | if __name__ == "__main__":
9 | app = QtWidgets.QApplication(sys.argv)
10 |
11 | w = QtWidgets.QWidget()
12 | w.resize(250, 150)
13 | w.move(300, 300)
14 | w.setWindowTitle("Test")
15 |
16 | layout = QtWidgets.QHBoxLayout(w)
17 | w.setLayout(layout)
18 |
19 | label = QtWidgets.QLabel("test", w)
20 | layout.addWidget(label)
21 |
22 | w.show()
23 | sys.exit(app.exec_())
--------------------------------------------------------------------------------
/Visualizer/requirements.txt:
--------------------------------------------------------------------------------
1 | cycler>=0.10.0
2 | matplotlib>=2.0.2
3 | numpy>=1.13.0
4 | pyparsing>=2.2.0
5 | python-dateutil>=2.6.0
6 | pytz>=2017.2
7 | six>=1.10.0
8 | PyQt5>=5.9
9 |
--------------------------------------------------------------------------------
/Visualizer/setup.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 9/12/2017
3 |
4 | # Run "python setup.py build" to create exe, can't be run from within a virtualenv
5 |
6 | import glob
7 | import os
8 | import os.path
9 | import shutil
10 | import sys
11 |
12 | from cx_Freeze import setup, Executable
13 |
14 | # Create a dist version of idea_relations
15 | if not os.path.isdir("../idea_rel_dist"):
16 | os.mkdir("../idea_rel_dist")
17 |
18 | for file in glob.glob("../idea_relations/*.py") + glob.glob("../idea_relations/*.sh") + glob.glob(
19 | "../idea_relations/*.bat"):
20 | shutil.copy2(file, "../idea_rel_dist/")
21 |
22 | base = None
23 | if sys.platform == "win32":
24 | base = "Win32GUI"
25 |
26 | additional_mods = ['numpy', 'numpy.core._methods', 'numpy.lib.format', 'scipy', 'nltk', 'scipy.interpolate', 'scipy.special']
27 |
28 |
29 | options = {
30 | 'build': {'build_exe': "../build"},
31 | 'build_exe': {'includes': additional_mods,
32 | 'include_files': [('../idea_rel_dist', 'idea_relations'), "Vis.ico"]
33 | },
34 | }
35 |
36 | setup(name="Visualizer",
37 | version="1.0",
38 | description="Visualizer",
39 | options=options,
40 | executables=[Executable("main.py", targetName="Visualizer", base=base, icon="Vis.ico")],
41 | )
42 |
--------------------------------------------------------------------------------
/Visualizer/startup.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 7/12/17
3 |
4 | """
5 | Run the preprocessor (ask for arguments, etc.) and feed the output into the gui
6 | """
7 |
8 | import datetime
9 | print(datetime.datetime.now())
10 | import os
11 | import os.path
12 | import subprocess
13 | import sys
14 |
15 |
16 | # Import matplotlib to ensure the backend it set to tk
17 | import matplotlib
18 | matplotlib.use("TKAgg")
19 |
20 | #from data_processor import main
21 | import Visualizer
22 |
23 | class Namespace:
24 | #def __getattr__(self, name):
25 | # return None
26 | pass
27 |
28 | def read_config_file(fname):
29 | if not os.path.isfile(fname):
30 | print("Error: Couldn't find file {0}".format(fname))
31 | sys.exit(1)
32 |
33 | f = open(fname, 'r')
34 |
35 | args = []
36 | for line in f.readlines():
37 | line = line.strip()
38 | if line == '':
39 | continue
40 |
41 | name, value = line.split('=')
42 |
43 | args.append("--{0}".format(name))
44 | args.append(value)
45 |
46 | return args
47 |
48 | def run_preprocessor(args):
49 | path = ["python", "main.py"] + args
50 | cwd = "../idea_relations/data_processor"
51 | subprocess.run(path, cwd=cwd)
52 |
53 | print(datetime.datetime.now())
54 | args = read_config_file("Keywords.config")
55 |
56 | print(datetime.datetime.now())
57 | run_preprocessor(args)
58 | #args = main.main(args, True)
59 |
60 | print(datetime.datetime.now())
61 | Visualizer.main("keywords_data.p")
62 |
--------------------------------------------------------------------------------
/Visualizer/templates/template.tex:
--------------------------------------------------------------------------------
1 | \documentclass[11pt]{{article}}
2 | \usepackage{{times}}
3 | \usepackage{{latexsym}}
4 |
5 | \usepackage{{amsmath}}
6 | \usepackage{{booktabs}}
7 | \usepackage{{array}}
8 | \usepackage{{multirow}}
9 | \usepackage{{graphicx}}
10 | \usepackage{{color}}
11 | \usepackage{{blindtext}}
12 | \usepackage{{subcaption}}
13 | \usepackage{{enumitem}}
14 | \usepackage{{multirow}}
15 |
16 | \newcommand{{\addFigure}}[2]{{\includegraphics[width=#1]{{#2}}}}
17 | \newcommand{{\para}}[1]{{\noindent{{\bf #1}}}}
18 | \newcommand{{\figref}}[1]{{Fig. \ref{{#1}}}}
19 | \newcommand{{\equationref}}[1]{{Eq. \ref{{#1}}}}
20 | \newcommand{{\secref}}[1]{{\S \ref{{#1}}}}
21 | \newcommand{{\tableref}}[1]{{Table \ref{{#1}}}}
22 | \newcommand{{\ideas}}{{ideas\xspace}}
23 | \newcommand{{\Ideas}}{{Ideas\xspace}}
24 | \newcommand{{\idea}}{{idea\xspace}}
25 | \newcommand{{\Idea}}{{Idea\xspace}}
26 | \newcommand{{\cooccurrence}}{{cooccurrence\xspace}}
27 | \newcommand{{\cooccurrences}}{{cooccurrences\xspace}}
28 | \newcommand{{\cooccur}}{{cooccur\xspace}}
29 | \newcommand{{\cooccurs}}{{cooccurs\xspace}}
30 | \newcommand{{\Cooccurrence}}{{Cooccurrence\xspace}}
31 | \newcommand{{\Cooccurrences}}{{Cooccurrences\xspace}}
32 | \newcommand{{\correlation}}{{prevalence correlation\xspace}}
33 | \newcommand{{\Correlation}}{{Prevalence correlation\xspace}}
34 | \newcommand{{\frequency}}{{prevalence\xspace}}
35 | \newcommand{{\pmi}}{{$\widehat{{\operatorname{{PMI}}}}$\xspace}}
36 | \newcommand{{\freqcorr}}{{$\hat{{r}}$\xspace}}
37 | \newcommand{{\kwords}}{{keywords\xspace}}
38 | \newcommand{{\kword}}{{keyword\xspace}}
39 | \newcommand{{\Kwords}}{{Keywords\xspace}}
40 | \newcommand{{\friends}}{{friendship\xspace}}
41 | \newcommand{{\tryst}}{{tryst\xspace}}
42 | \newcommand{{\armsrace}}{{arms-race\xspace}}
43 | \newcommand{{\headtohead}}{{head-to-head\xspace}}
44 | \newcommand{{\Friends}}{{Friendship\xspace}}
45 | \newcommand{{\Tryst}}{{Tryst\xspace}}
46 | \newcommand{{\Armsrace}}{{Arms-race\xspace}}
47 | \newcommand{{\Headtohead}}{{Head-to-head\xspace}}
48 |
49 | \newcommand{{\ideaname}}[1]{{{{\small\sf #1}}\xspace}}
50 | \newcommand{{\ideapair}}[2]{{(\ideaname{{#1}}, \ideaname{{#2}})}}
51 | \definecolor{{friendscolor}}{{RGB}}{{19, 126, 109}}
52 | \definecolor{{armsracecolor}}{{RGB}}{{68, 142, 228}}
53 | \definecolor{{headtoheadcolor}}{{RGB}}{{152, 0, 2}}
54 | \definecolor{{trystcolor}}{{RGB}}{{207, 98, 117}}
55 | \newcommand{{\formalideas}}{{\mathcal{{I}}}}
56 |
57 | \title{{Idea relations}}
58 |
59 | \author{{}}
60 | \begin{{document}}
61 | \maketitle
62 | \section{{Overall distributions}}
63 |
64 | % \figref{{fig:joint}} shows the joint distributions between PMI and prevalence correlation.
65 | % \figref{{fig:average}} shows the average strength of the top 25 pairs in each category.
66 | \begin{{figure*}}[htb!]
67 | \centering
68 | \begin{{subfigure}}{{0.45\textwidth}}
69 | \addFigure{{\textwidth}}{joint_file}
70 | \caption{{Joint distribution between PMI and prevalence correlation.}}
71 | \label{{fig:joint}}
72 | \end{{subfigure}}
73 | \hfill
74 | \begin{{subfigure}}{{0.45\textwidth}}
75 | \addFigure{{\textwidth}}{average_file}
76 | \caption{{Strength of the top 25 pairs in each category.}}
77 | \label{{fig:average}}
78 | \end{{subfigure}}
79 | \end{{figure*}}
80 |
81 |
82 |
83 | \section{{Top relation plots}}
84 | \begin{{figure*}}[htb!]
85 | \centering
86 | {{\large \textcolor{{friendscolor}}{{\Friends}}}}\\
87 | \begin{{subfigure}}[t]{{0.22\textwidth}}
88 | \addFigure{{\textwidth}}{friends_1}
89 | \caption{{\Friends (\#1).}}
90 | \end{{subfigure}}
91 | \hfill
92 | \begin{{subfigure}}[t]{{0.22\textwidth}}
93 | \addFigure{{\textwidth}}{friends_2}
94 | \caption{{\Friends (\#2).}}
95 | \end{{subfigure}}
96 | \hfill
97 | \begin{{subfigure}}[t]{{0.22\textwidth}}
98 | \addFigure{{\textwidth}}{friends_3}
99 | \caption{{\Friends (\#3).}}
100 | \end{{subfigure}}
101 | \hfill
102 | \begin{{subfigure}}[t]{{0.22\textwidth}}
103 | \addFigure{{\textwidth}}{friends_4}
104 | \caption{{\Friends (\#4).}}
105 | \end{{subfigure}}\\
106 | {{\large \textcolor{{headtoheadcolor}}{{\Headtohead}}}}\\
107 | \begin{{subfigure}}[t]{{0.22\textwidth}}
108 | \addFigure{{\textwidth}}{headtohead_1}
109 | \caption{{\Headtohead (\#1).}}
110 | \end{{subfigure}}
111 | \hfill
112 | \begin{{subfigure}}[t]{{0.22\textwidth}}
113 | \addFigure{{\textwidth}}{headtohead_2}
114 | \caption{{\Headtohead (\#2).}}
115 | \end{{subfigure}}
116 | \hfill
117 | \begin{{subfigure}}[t]{{0.22\textwidth}}
118 | \addFigure{{\textwidth}}{headtohead_3}
119 | \caption{{\Headtohead (\#3).}}
120 | \end{{subfigure}}
121 | \hfill
122 | \begin{{subfigure}}[t]{{0.22\textwidth}}
123 | \addFigure{{\textwidth}}{headtohead_4}
124 | \caption{{\Headtohead (\#4).}}
125 | \end{{subfigure}}\\
126 | {{\large \textcolor{{armsracecolor}}{{\Armsrace}}}}\\
127 | \begin{{subfigure}}[t]{{0.22\textwidth}}
128 | \addFigure{{\textwidth}}{armsrace_1}
129 | \caption{{\Armsrace (\#1).}}
130 | \end{{subfigure}}
131 | \hfill
132 | \begin{{subfigure}}[t]{{0.22\textwidth}}
133 | \addFigure{{\textwidth}}{armsrace_2}
134 | \caption{{\Armsrace (\#2).}}
135 | \end{{subfigure}}
136 | \hfill
137 | \begin{{subfigure}}[t]{{0.22\textwidth}}
138 | \addFigure{{\textwidth}}{armsrace_3}
139 | \caption{{\Armsrace (\#3).}}
140 | \end{{subfigure}}
141 | \hfill
142 | \begin{{subfigure}}[t]{{0.22\textwidth}}
143 | \addFigure{{\textwidth}}{armsrace_4}
144 | \caption{{\Armsrace (\#4).}}
145 | \end{{subfigure}}\\
146 | {{\large \textcolor{{trystcolor}}{{\Tryst}}}}\\
147 | \begin{{subfigure}}[t]{{0.22\textwidth}}
148 | \addFigure{{\textwidth}}{tryst_1}
149 | \caption{{\Tryst (\#1).}}
150 | \end{{subfigure}}
151 | \hfill
152 | \begin{{subfigure}}[t]{{0.22\textwidth}}
153 | \addFigure{{\textwidth}}{tryst_2}
154 | \caption{{\Tryst (\#2).}}
155 | \end{{subfigure}}
156 | \hfill
157 | \begin{{subfigure}}[t]{{0.22\textwidth}}
158 | \addFigure{{\textwidth}}{tryst_3}
159 | \caption{{\Tryst (\#3).}}
160 | \end{{subfigure}}
161 | \hfill
162 | \begin{{subfigure}}[t]{{0.22\textwidth}}
163 | \addFigure{{\textwidth}}{tryst_4}
164 | \caption{{\Tryst (\#4).}}
165 | \end{{subfigure}}
166 | \caption{{Top four figures in each category, more careful investigation is required to interpret these results. Also explore further down the list (e.g., top 50) to get a better understanding.}}
167 | \label{{fig:top}}
168 | \end{{figure*}}
169 | \clearpage
170 |
171 | \section{{Relation tables}}
172 | \begin{{table*}}[htb!]
173 | \centering
174 | \caption{{Relation between ideas. This table shows top pairs. In the table/ directory, there is another file with top 50 pairs, which is worth further investigation.}}
175 | \label{{tab:top}}
176 | \scriptsize
177 | \input{table_file}
178 | \end{{table*}}
179 | \end{{document}}
180 |
181 |
--------------------------------------------------------------------------------
/Visualizer/ui/GeneratePy.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | call ..\venv\Scripts\activate.bat
4 |
5 | for %%f in (*.ui) do (
6 |
7 | pyuic5 -o "%%~nf.py" "%%~nf.ui"
8 | )
9 |
--------------------------------------------------------------------------------
/Visualizer/ui/GeneratePy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | source ../venv/bin/activate
4 |
5 | for f in *.ui
6 | do
7 | filename=$(basename "$f")
8 | filename="${filename%.*}"
9 | pyuic5 -o "$filename.py" $f
10 | done
11 |
--------------------------------------------------------------------------------
/Visualizer/ui/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nwrush/Visualization/bc134aa02156956ea3644b34d491da9f0e9f63ae/Visualizer/ui/__init__.py
--------------------------------------------------------------------------------
/Visualizer/ui/main_window.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'main_window.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.9
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 | from PyQt5 import QtCore, QtGui, QtWidgets
10 |
11 | class Ui_mainWindow(object):
12 | def setupUi(self, mainWindow):
13 | mainWindow.setObjectName("mainWindow")
14 | mainWindow.resize(800, 600)
15 | icon = QtGui.QIcon()
16 | icon.addPixmap(QtGui.QPixmap("Vis.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
17 | mainWindow.setWindowIcon(icon)
18 | self.main_widget = QtWidgets.QWidget(mainWindow)
19 | self.main_widget.setObjectName("main_widget")
20 | self.horizontalLayout = QtWidgets.QHBoxLayout(self.main_widget)
21 | self.horizontalLayout.setObjectName("horizontalLayout")
22 | self.tabWidget = QtWidgets.QTabWidget(self.main_widget)
23 | self.tabWidget.setTabsClosable(True)
24 | self.tabWidget.setObjectName("tabWidget")
25 | self.horizontalLayout.addWidget(self.tabWidget)
26 | mainWindow.setCentralWidget(self.main_widget)
27 | self.menubar = QtWidgets.QMenuBar(mainWindow)
28 | self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
29 | self.menubar.setObjectName("menubar")
30 | self.openMenu = QtWidgets.QMenu(self.menubar)
31 | self.openMenu.setEnabled(True)
32 | self.openMenu.setObjectName("openMenu")
33 | self.visualizationMenu = QtWidgets.QMenu(self.menubar)
34 | self.visualizationMenu.setObjectName("visualizationMenu")
35 | mainWindow.setMenuBar(self.menubar)
36 | self.statusbar = QtWidgets.QStatusBar(mainWindow)
37 | self.statusbar.setObjectName("statusbar")
38 | mainWindow.setStatusBar(self.statusbar)
39 | self.actionOpen = QtWidgets.QAction(mainWindow)
40 | self.actionOpen.setVisible(True)
41 | self.actionOpen.setObjectName("actionOpen")
42 | self.actionSave_PMI = QtWidgets.QAction(mainWindow)
43 | self.actionSave_PMI.setObjectName("actionSave_PMI")
44 | self.actionSave_TS = QtWidgets.QAction(mainWindow)
45 | self.actionSave_TS.setObjectName("actionSave_TS")
46 | self.actionSave_Both = QtWidgets.QAction(mainWindow)
47 | self.actionSave_Both.setObjectName("actionSave_Both")
48 | self.actionSave = QtWidgets.QAction(mainWindow)
49 | self.actionSave.setObjectName("actionSave")
50 | self.openMenu.addAction(self.actionOpen)
51 | self.openMenu.addAction(self.actionSave)
52 | self.visualizationMenu.addAction(self.actionSave_PMI)
53 | self.visualizationMenu.addAction(self.actionSave_TS)
54 | self.visualizationMenu.addAction(self.actionSave_Both)
55 | self.menubar.addAction(self.openMenu.menuAction())
56 | self.menubar.addAction(self.visualizationMenu.menuAction())
57 |
58 | self.retranslateUi(mainWindow)
59 | self.tabWidget.setCurrentIndex(-1)
60 | QtCore.QMetaObject.connectSlotsByName(mainWindow)
61 |
62 | def retranslateUi(self, mainWindow):
63 | _translate = QtCore.QCoreApplication.translate
64 | mainWindow.setWindowTitle(_translate("mainWindow", "MainWindow"))
65 | self.openMenu.setTitle(_translate("mainWindow", "File"))
66 | self.visualizationMenu.setTitle(_translate("mainWindow", "Visualization"))
67 | self.actionOpen.setText(_translate("mainWindow", "Open"))
68 | self.actionOpen.setShortcut(_translate("mainWindow", "Ctrl+O"))
69 | self.actionSave_PMI.setText(_translate("mainWindow", "Save PMI"))
70 | self.actionSave_TS.setText(_translate("mainWindow", "Save TS"))
71 | self.actionSave_Both.setText(_translate("mainWindow", "Save Both"))
72 | self.actionSave.setText(_translate("mainWindow", "Save"))
73 | self.actionSave.setShortcut(_translate("mainWindow", "Ctrl+S"))
74 |
75 |
--------------------------------------------------------------------------------
/Visualizer/ui/main_window.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | mainWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 800
10 | 600
11 |
12 |
13 |
14 | MainWindow
15 |
16 |
17 |
18 | Vis.icoVis.ico
19 |
20 |
21 |
22 | -
23 |
24 |
25 | -1
26 |
27 |
28 | true
29 |
30 |
31 |
32 |
33 |
34 |
64 |
65 |
66 |
67 | Open
68 |
69 |
70 | Ctrl+O
71 |
72 |
73 | true
74 |
75 |
76 |
77 |
78 | Save PMI
79 |
80 |
81 |
82 |
83 | Save TS
84 |
85 |
86 |
87 |
88 | Save Both
89 |
90 |
91 |
92 |
93 | Save
94 |
95 |
96 | Ctrl+S
97 |
98 |
99 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/Visualizer/ui/pmi_control_panel_horiz.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'pmi_control_panel_horiz.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.9
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 | from PyQt5 import QtCore, QtGui, QtWidgets
10 |
11 | class Ui_pmi_control_panel(object):
12 | def setupUi(self, pmi_control_panel):
13 | pmi_control_panel.setObjectName("pmi_control_panel")
14 | pmi_control_panel.resize(623, 200)
15 | pmi_control_panel.setMaximumSize(QtCore.QSize(16777215, 200))
16 | self.horizontalLayout = QtWidgets.QHBoxLayout(pmi_control_panel)
17 | self.horizontalLayout.setObjectName("horizontalLayout")
18 | self.groupBox_2 = QtWidgets.QGroupBox(pmi_control_panel)
19 | self.groupBox_2.setObjectName("groupBox_2")
20 | self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.groupBox_2)
21 | self.verticalLayout_3.setObjectName("verticalLayout_3")
22 | self.filteredList = QtWidgets.QListWidget(self.groupBox_2)
23 | self.filteredList.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
24 | self.filteredList.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
25 | self.filteredList.setObjectName("filteredList")
26 | self.verticalLayout_3.addWidget(self.filteredList)
27 | self.resetButton = QtWidgets.QPushButton(self.groupBox_2)
28 | self.resetButton.setObjectName("resetButton")
29 | self.verticalLayout_3.addWidget(self.resetButton)
30 | self.horizontalLayout.addWidget(self.groupBox_2)
31 |
32 | self.retranslateUi(pmi_control_panel)
33 | QtCore.QMetaObject.connectSlotsByName(pmi_control_panel)
34 |
35 | def retranslateUi(self, pmi_control_panel):
36 | _translate = QtCore.QCoreApplication.translate
37 | pmi_control_panel.setWindowTitle(_translate("pmi_control_panel", "Form"))
38 | self.groupBox_2.setTitle(_translate("pmi_control_panel", "Filtered By"))
39 | self.resetButton.setText(_translate("pmi_control_panel", "Reset"))
40 |
41 |
--------------------------------------------------------------------------------
/Visualizer/ui/pmi_control_panel_horiz.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | pmi_control_panel
4 |
5 |
6 |
7 | 0
8 | 0
9 | 623
10 | 200
11 |
12 |
13 |
14 |
15 | 16777215
16 | 200
17 |
18 |
19 |
20 | Form
21 |
22 |
23 | -
24 |
25 |
26 | Filtered By
27 |
28 |
29 |
-
30 |
31 |
32 | QAbstractItemView::NoEditTriggers
33 |
34 |
35 | QAbstractItemView::NoSelection
36 |
37 |
38 |
39 | -
40 |
41 |
42 | Reset
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/Visualizer/ui/pmi_control_panel_vert.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'pmi_control_panel_vert.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.9
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 | from PyQt5 import QtCore, QtGui, QtWidgets
10 |
11 | class Ui_pmi_control_panel(object):
12 | def setupUi(self, pmi_control_panel):
13 | pmi_control_panel.setObjectName("pmi_control_panel")
14 | pmi_control_panel.resize(258, 415)
15 | self.verticalLayout = QtWidgets.QVBoxLayout(pmi_control_panel)
16 | self.verticalLayout.setObjectName("verticalLayout")
17 | self.horizontalLayout = QtWidgets.QHBoxLayout()
18 | self.horizontalLayout.setObjectName("horizontalLayout")
19 | self.groupBox = QtWidgets.QGroupBox(pmi_control_panel)
20 | font = QtGui.QFont()
21 | font.setPointSize(10)
22 | self.groupBox.setFont(font)
23 | self.groupBox.setObjectName("groupBox")
24 | self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.groupBox)
25 | self.verticalLayout_4.setObjectName("verticalLayout_4")
26 | self.filteredList = QtWidgets.QListWidget(self.groupBox)
27 | self.filteredList.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
28 | self.filteredList.setWordWrap(False)
29 | self.filteredList.setObjectName("filteredList")
30 | self.verticalLayout_4.addWidget(self.filteredList)
31 | self.horizontalLayout.addWidget(self.groupBox)
32 | self.verticalLayout.addLayout(self.horizontalLayout)
33 | self.resetButton = QtWidgets.QPushButton(pmi_control_panel)
34 | self.resetButton.setObjectName("resetButton")
35 | self.verticalLayout.addWidget(self.resetButton)
36 | self.line = QtWidgets.QFrame(pmi_control_panel)
37 | self.line.setFrameShape(QtWidgets.QFrame.HLine)
38 | self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
39 | self.line.setObjectName("line")
40 | self.verticalLayout.addWidget(self.line)
41 | self.colorLabels = QtWidgets.QGroupBox(pmi_control_panel)
42 | self.colorLabels.setEnabled(True)
43 | self.colorLabels.setFlat(False)
44 | self.colorLabels.setObjectName("colorLabels")
45 | self.gridLayout = QtWidgets.QGridLayout(self.colorLabels)
46 | self.gridLayout.setObjectName("gridLayout")
47 | self.colorLabelsLayout = QtWidgets.QGridLayout()
48 | self.colorLabelsLayout.setObjectName("colorLabelsLayout")
49 | self.headtoheadLabel = QtWidgets.QLabel(self.colorLabels)
50 | font = QtGui.QFont()
51 | font.setPointSize(9)
52 | self.headtoheadLabel.setFont(font)
53 | self.headtoheadLabel.setAutoFillBackground(True)
54 | self.headtoheadLabel.setAlignment(QtCore.Qt.AlignCenter)
55 | self.headtoheadLabel.setObjectName("headtoheadLabel")
56 | self.colorLabelsLayout.addWidget(self.headtoheadLabel, 1, 0, 1, 1)
57 | self.trystLabel = QtWidgets.QLabel(self.colorLabels)
58 | font = QtGui.QFont()
59 | font.setPointSize(9)
60 | self.trystLabel.setFont(font)
61 | self.trystLabel.setAutoFillBackground(True)
62 | self.trystLabel.setAlignment(QtCore.Qt.AlignCenter)
63 | self.trystLabel.setObjectName("trystLabel")
64 | self.colorLabelsLayout.addWidget(self.trystLabel, 0, 0, 1, 1)
65 | self.friendsLabel = QtWidgets.QLabel(self.colorLabels)
66 | font = QtGui.QFont()
67 | font.setPointSize(9)
68 | self.friendsLabel.setFont(font)
69 | self.friendsLabel.setAutoFillBackground(True)
70 | self.friendsLabel.setAlignment(QtCore.Qt.AlignCenter)
71 | self.friendsLabel.setObjectName("friendsLabel")
72 | self.colorLabelsLayout.addWidget(self.friendsLabel, 0, 1, 1, 1)
73 | self.armsraceLabel = QtWidgets.QLabel(self.colorLabels)
74 | font = QtGui.QFont()
75 | font.setPointSize(9)
76 | self.armsraceLabel.setFont(font)
77 | self.armsraceLabel.setAutoFillBackground(True)
78 | self.armsraceLabel.setAlignment(QtCore.Qt.AlignCenter)
79 | self.armsraceLabel.setObjectName("armsraceLabel")
80 | self.colorLabelsLayout.addWidget(self.armsraceLabel, 1, 1, 1, 1)
81 | self.gridLayout.addLayout(self.colorLabelsLayout, 0, 0, 1, 1)
82 | self.verticalLayout.addWidget(self.colorLabels)
83 |
84 | self.retranslateUi(pmi_control_panel)
85 | QtCore.QMetaObject.connectSlotsByName(pmi_control_panel)
86 |
87 | def retranslateUi(self, pmi_control_panel):
88 | _translate = QtCore.QCoreApplication.translate
89 | pmi_control_panel.setWindowTitle(_translate("pmi_control_panel", "Form"))
90 | self.groupBox.setTitle(_translate("pmi_control_panel", "Filtered By"))
91 | self.resetButton.setText(_translate("pmi_control_panel", "Reset"))
92 | self.colorLabels.setTitle(_translate("pmi_control_panel", "Legend"))
93 | self.headtoheadLabel.setText(_translate("pmi_control_panel", "Head-To-Head"))
94 | self.trystLabel.setText(_translate("pmi_control_panel", "Tryst"))
95 | self.friendsLabel.setText(_translate("pmi_control_panel", "Friends"))
96 | self.armsraceLabel.setText(_translate("pmi_control_panel", "Arms-Race"))
97 |
98 |
--------------------------------------------------------------------------------
/Visualizer/ui/pmi_control_panel_vert.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | pmi_control_panel
4 |
5 |
6 |
7 | 0
8 | 0
9 | 258
10 | 415
11 |
12 |
13 |
14 | Form
15 |
16 |
17 | -
18 |
19 |
-
20 |
21 |
22 |
23 | 10
24 |
25 |
26 |
27 | Filtered By
28 |
29 |
30 |
-
31 |
32 |
33 | QAbstractItemView::NoSelection
34 |
35 |
36 | false
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | -
46 |
47 |
48 | Reset
49 |
50 |
51 |
52 | -
53 |
54 |
55 | Qt::Horizontal
56 |
57 |
58 |
59 | -
60 |
61 |
62 | true
63 |
64 |
65 | Legend
66 |
67 |
68 | false
69 |
70 |
71 |
-
72 |
73 |
-
74 |
75 |
76 |
77 | 9
78 |
79 |
80 |
81 | true
82 |
83 |
84 | Head-To-Head
85 |
86 |
87 | Qt::AlignCenter
88 |
89 |
90 |
91 | -
92 |
93 |
94 |
95 | 9
96 |
97 |
98 |
99 | true
100 |
101 |
102 | Tryst
103 |
104 |
105 | Qt::AlignCenter
106 |
107 |
108 |
109 | -
110 |
111 |
112 |
113 | 9
114 |
115 |
116 |
117 | true
118 |
119 |
120 | Friends
121 |
122 |
123 | Qt::AlignCenter
124 |
125 |
126 |
127 | -
128 |
129 |
130 |
131 | 9
132 |
133 |
134 |
135 | true
136 |
137 |
138 | Arms-Race
139 |
140 |
141 | Qt::AlignCenter
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
--------------------------------------------------------------------------------
/Visualizer/ui/preprocessor_form.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'preprocessor_form.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.9
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 | from PyQt5 import QtCore, QtGui, QtWidgets
10 |
11 | class Ui_preprocessorForm(object):
12 | def setupUi(self, preprocessorForm):
13 | preprocessorForm.setObjectName("preprocessorForm")
14 | preprocessorForm.resize(784, 591)
15 | self.formLayout = QtWidgets.QFormLayout(preprocessorForm)
16 | self.formLayout.setObjectName("formLayout")
17 | self.label = QtWidgets.QLabel(preprocessorForm)
18 | font = QtGui.QFont()
19 | font.setPointSize(10)
20 | self.label.setFont(font)
21 | self.label.setObjectName("label")
22 | self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label)
23 | self.optionBox = QtWidgets.QComboBox(preprocessorForm)
24 | self.optionBox.setObjectName("optionBox")
25 | self.optionBox.addItem("")
26 | self.optionBox.addItem("")
27 | self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.optionBox)
28 | self.label_2 = QtWidgets.QLabel(preprocessorForm)
29 | font = QtGui.QFont()
30 | font.setPointSize(10)
31 | self.label_2.setFont(font)
32 | self.label_2.setObjectName("label_2")
33 | self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_2)
34 | self.horizontalLayout = QtWidgets.QHBoxLayout()
35 | self.horizontalLayout.setObjectName("horizontalLayout")
36 | self.inputFile = QtWidgets.QLineEdit(preprocessorForm)
37 | self.inputFile.setFocusPolicy(QtCore.Qt.StrongFocus)
38 | self.inputFile.setAutoFillBackground(False)
39 | self.inputFile.setStyleSheet("base: rgb(170, 255, 255)")
40 | self.inputFile.setObjectName("inputFile")
41 | self.horizontalLayout.addWidget(self.inputFile)
42 | self.inputFileBtn = QtWidgets.QPushButton(preprocessorForm)
43 | self.inputFileBtn.setFocusPolicy(QtCore.Qt.ClickFocus)
44 | self.inputFileBtn.setObjectName("inputFileBtn")
45 | self.horizontalLayout.addWidget(self.inputFileBtn)
46 | self.formLayout.setLayout(2, QtWidgets.QFormLayout.FieldRole, self.horizontalLayout)
47 | self.label_5 = QtWidgets.QLabel(preprocessorForm)
48 | font = QtGui.QFont()
49 | font.setPointSize(10)
50 | self.label_5.setFont(font)
51 | self.label_5.setObjectName("label_5")
52 | self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_5)
53 | self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
54 | self.horizontalLayout_4.setObjectName("horizontalLayout_4")
55 | self.bckFile = QtWidgets.QLineEdit(preprocessorForm)
56 | self.bckFile.setFocusPolicy(QtCore.Qt.StrongFocus)
57 | self.bckFile.setObjectName("bckFile")
58 | self.horizontalLayout_4.addWidget(self.bckFile)
59 | self.bckFileBtn = QtWidgets.QPushButton(preprocessorForm)
60 | self.bckFileBtn.setFocusPolicy(QtCore.Qt.ClickFocus)
61 | self.bckFileBtn.setObjectName("bckFileBtn")
62 | self.horizontalLayout_4.addWidget(self.bckFileBtn)
63 | self.formLayout.setLayout(4, QtWidgets.QFormLayout.FieldRole, self.horizontalLayout_4)
64 | self.label_4 = QtWidgets.QLabel(preprocessorForm)
65 | font = QtGui.QFont()
66 | font.setPointSize(10)
67 | self.label_4.setFont(font)
68 | self.label_4.setObjectName("label_4")
69 | self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.label_4)
70 | self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
71 | self.horizontalLayout_5.setObjectName("horizontalLayout_5")
72 | self.malletDir = QtWidgets.QLineEdit(preprocessorForm)
73 | self.malletDir.setFocusPolicy(QtCore.Qt.StrongFocus)
74 | self.malletDir.setObjectName("malletDir")
75 | self.horizontalLayout_5.addWidget(self.malletDir)
76 | self.malletDirBtn = QtWidgets.QPushButton(preprocessorForm)
77 | self.malletDirBtn.setFocusPolicy(QtCore.Qt.ClickFocus)
78 | self.malletDirBtn.setObjectName("malletDirBtn")
79 | self.horizontalLayout_5.addWidget(self.malletDirBtn)
80 | self.formLayout.setLayout(6, QtWidgets.QFormLayout.FieldRole, self.horizontalLayout_5)
81 | self.label_3 = QtWidgets.QLabel(preprocessorForm)
82 | font = QtGui.QFont()
83 | font.setPointSize(10)
84 | self.label_3.setFont(font)
85 | self.label_3.setObjectName("label_3")
86 | self.formLayout.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.label_3)
87 | self.groupBox = QtWidgets.QComboBox(preprocessorForm)
88 | self.groupBox.setObjectName("groupBox")
89 | self.groupBox.addItem("")
90 | self.groupBox.addItem("")
91 | self.groupBox.addItem("")
92 | self.formLayout.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.groupBox)
93 | self.label_8 = QtWidgets.QLabel(preprocessorForm)
94 | font = QtGui.QFont()
95 | font.setPointSize(10)
96 | self.label_8.setFont(font)
97 | self.label_8.setObjectName("label_8")
98 | self.formLayout.setWidget(10, QtWidgets.QFormLayout.LabelRole, self.label_8)
99 | self.prefix = QtWidgets.QLineEdit(preprocessorForm)
100 | self.prefix.setObjectName("prefix")
101 | self.formLayout.setWidget(10, QtWidgets.QFormLayout.FieldRole, self.prefix)
102 | self.label_9 = QtWidgets.QLabel(preprocessorForm)
103 | font = QtGui.QFont()
104 | font.setPointSize(10)
105 | self.label_9.setFont(font)
106 | self.label_9.setObjectName("label_9")
107 | self.formLayout.setWidget(12, QtWidgets.QFormLayout.LabelRole, self.label_9)
108 | self.numIdeas = QtWidgets.QLineEdit(preprocessorForm)
109 | self.numIdeas.setObjectName("numIdeas")
110 | self.formLayout.setWidget(12, QtWidgets.QFormLayout.FieldRole, self.numIdeas)
111 | self.label_10 = QtWidgets.QLabel(preprocessorForm)
112 | font = QtGui.QFont()
113 | font.setPointSize(10)
114 | self.label_10.setFont(font)
115 | self.label_10.setObjectName("label_10")
116 | self.formLayout.setWidget(14, QtWidgets.QFormLayout.LabelRole, self.label_10)
117 | self.tokenizeBox = QtWidgets.QCheckBox(preprocessorForm)
118 | self.tokenizeBox.setText("")
119 | self.tokenizeBox.setObjectName("tokenizeBox")
120 | self.formLayout.setWidget(14, QtWidgets.QFormLayout.FieldRole, self.tokenizeBox)
121 | self.label_11 = QtWidgets.QLabel(preprocessorForm)
122 | font = QtGui.QFont()
123 | font.setPointSize(10)
124 | self.label_11.setFont(font)
125 | self.label_11.setObjectName("label_11")
126 | self.formLayout.setWidget(15, QtWidgets.QFormLayout.LabelRole, self.label_11)
127 | self.lemmatizeBox = QtWidgets.QCheckBox(preprocessorForm)
128 | self.lemmatizeBox.setText("")
129 | self.lemmatizeBox.setObjectName("lemmatizeBox")
130 | self.formLayout.setWidget(15, QtWidgets.QFormLayout.FieldRole, self.lemmatizeBox)
131 | self.label_12 = QtWidgets.QLabel(preprocessorForm)
132 | font = QtGui.QFont()
133 | font.setPointSize(10)
134 | self.label_12.setFont(font)
135 | self.label_12.setObjectName("label_12")
136 | self.formLayout.setWidget(16, QtWidgets.QFormLayout.LabelRole, self.label_12)
137 | self.stopwordBox = QtWidgets.QCheckBox(preprocessorForm)
138 | self.stopwordBox.setText("")
139 | self.stopwordBox.setObjectName("stopwordBox")
140 | self.formLayout.setWidget(16, QtWidgets.QFormLayout.FieldRole, self.stopwordBox)
141 | self.outputDirLbl = QtWidgets.QLabel(preprocessorForm)
142 | font = QtGui.QFont()
143 | font.setPointSize(10)
144 | self.outputDirLbl.setFont(font)
145 | self.outputDirLbl.setObjectName("outputDirLbl")
146 | self.formLayout.setWidget(19, QtWidgets.QFormLayout.LabelRole, self.outputDirLbl)
147 | self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
148 | self.horizontalLayout_2.setObjectName("horizontalLayout_2")
149 | self.outputDir = QtWidgets.QLineEdit(preprocessorForm)
150 | self.outputDir.setFocusPolicy(QtCore.Qt.StrongFocus)
151 | self.outputDir.setObjectName("outputDir")
152 | self.horizontalLayout_2.addWidget(self.outputDir)
153 | self.outputDirBtn = QtWidgets.QPushButton(preprocessorForm)
154 | self.outputDirBtn.setFocusPolicy(QtCore.Qt.ClickFocus)
155 | self.outputDirBtn.setObjectName("outputDirBtn")
156 | self.horizontalLayout_2.addWidget(self.outputDirBtn)
157 | self.formLayout.setLayout(19, QtWidgets.QFormLayout.FieldRole, self.horizontalLayout_2)
158 | self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
159 | self.horizontalLayout_3.setObjectName("horizontalLayout_3")
160 | self.finalDir = QtWidgets.QLineEdit(preprocessorForm)
161 | self.finalDir.setFocusPolicy(QtCore.Qt.StrongFocus)
162 | self.finalDir.setObjectName("finalDir")
163 | self.horizontalLayout_3.addWidget(self.finalDir)
164 | self.finalDirBtn = QtWidgets.QPushButton(preprocessorForm)
165 | self.finalDirBtn.setFocusPolicy(QtCore.Qt.ClickFocus)
166 | self.finalDirBtn.setObjectName("finalDirBtn")
167 | self.horizontalLayout_3.addWidget(self.finalDirBtn)
168 | self.formLayout.setLayout(20, QtWidgets.QFormLayout.FieldRole, self.horizontalLayout_3)
169 | self.finalDirLbl = QtWidgets.QLabel(preprocessorForm)
170 | font = QtGui.QFont()
171 | font.setPointSize(10)
172 | self.finalDirLbl.setFont(font)
173 | self.finalDirLbl.setObjectName("finalDirLbl")
174 | self.formLayout.setWidget(20, QtWidgets.QFormLayout.LabelRole, self.finalDirLbl)
175 | self.line = QtWidgets.QFrame(preprocessorForm)
176 | self.line.setFrameShape(QtWidgets.QFrame.HLine)
177 | self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
178 | self.line.setObjectName("line")
179 | self.formLayout.setWidget(17, QtWidgets.QFormLayout.SpanningRole, self.line)
180 | self.label_13 = QtWidgets.QLabel(preprocessorForm)
181 | font = QtGui.QFont()
182 | font.setPointSize(10)
183 | self.label_13.setFont(font)
184 | self.label_13.setObjectName("label_13")
185 | self.formLayout.setWidget(18, QtWidgets.QFormLayout.LabelRole, self.label_13)
186 | self.showAdvancedBox = QtWidgets.QCheckBox(preprocessorForm)
187 | self.showAdvancedBox.setText("")
188 | self.showAdvancedBox.setObjectName("showAdvancedBox")
189 | self.formLayout.setWidget(18, QtWidgets.QFormLayout.FieldRole, self.showAdvancedBox)
190 |
191 | self.retranslateUi(preprocessorForm)
192 | QtCore.QMetaObject.connectSlotsByName(preprocessorForm)
193 | preprocessorForm.setTabOrder(self.optionBox, self.inputFile)
194 | preprocessorForm.setTabOrder(self.inputFile, self.bckFile)
195 | preprocessorForm.setTabOrder(self.bckFile, self.malletDir)
196 | preprocessorForm.setTabOrder(self.malletDir, self.groupBox)
197 | preprocessorForm.setTabOrder(self.groupBox, self.prefix)
198 | preprocessorForm.setTabOrder(self.prefix, self.numIdeas)
199 | preprocessorForm.setTabOrder(self.numIdeas, self.tokenizeBox)
200 | preprocessorForm.setTabOrder(self.tokenizeBox, self.lemmatizeBox)
201 | preprocessorForm.setTabOrder(self.lemmatizeBox, self.stopwordBox)
202 |
203 | def retranslateUi(self, preprocessorForm):
204 | _translate = QtCore.QCoreApplication.translate
205 | preprocessorForm.setWindowTitle(_translate("preprocessorForm", "Form"))
206 | self.label.setText(_translate("preprocessorForm", "Option"))
207 | self.optionBox.setItemText(0, _translate("preprocessorForm", "Keywords"))
208 | self.optionBox.setItemText(1, _translate("preprocessorForm", "Topics"))
209 | self.label_2.setText(_translate("preprocessorForm", "Input File"))
210 | self.inputFileBtn.setText(_translate("preprocessorForm", "..."))
211 | self.label_5.setText(_translate("preprocessorForm", "Background File"))
212 | self.bckFileBtn.setText(_translate("preprocessorForm", "..."))
213 | self.label_4.setText(_translate("preprocessorForm", "Mallet Bin Directory"))
214 | self.malletDirBtn.setText(_translate("preprocessorForm", "..."))
215 | self.label_3.setText(_translate("preprocessorForm", "Group By"))
216 | self.groupBox.setItemText(0, _translate("preprocessorForm", "Year"))
217 | self.groupBox.setItemText(1, _translate("preprocessorForm", "Month"))
218 | self.groupBox.setItemText(2, _translate("preprocessorForm", "Quarter"))
219 | self.label_8.setText(_translate("preprocessorForm", "Exploration Name"))
220 | self.label_9.setText(_translate("preprocessorForm", "Number of Ideas"))
221 | self.label_10.setText(_translate("preprocessorForm", "Tokenize"))
222 | self.label_11.setText(_translate("preprocessorForm", "Lemmatize"))
223 | self.label_12.setText(_translate("preprocessorForm", "No Stop Words"))
224 | self.outputDirLbl.setText(_translate("preprocessorForm", "Output Directory"))
225 | self.outputDirBtn.setText(_translate("preprocessorForm", "..."))
226 | self.finalDirBtn.setText(_translate("preprocessorForm", "..."))
227 | self.finalDirLbl.setText(_translate("preprocessorForm", "Final Output Directory"))
228 | self.label_13.setText(_translate("preprocessorForm", "Advanced Options"))
229 |
230 |
--------------------------------------------------------------------------------
/Visualizer/ui/preprocessor_form.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | preprocessorForm
4 |
5 |
6 |
7 | 0
8 | 0
9 | 784
10 | 591
11 |
12 |
13 |
14 | Form
15 |
16 |
17 | -
18 |
19 |
20 |
21 | 10
22 |
23 |
24 |
25 | Option
26 |
27 |
28 |
29 | -
30 |
31 |
-
32 |
33 | Keywords
34 |
35 |
36 | -
37 |
38 | Topics
39 |
40 |
41 |
42 |
43 | -
44 |
45 |
46 |
47 | 10
48 |
49 |
50 |
51 | Input File
52 |
53 |
54 |
55 | -
56 |
57 |
-
58 |
59 |
60 | Qt::StrongFocus
61 |
62 |
63 | false
64 |
65 |
66 | base: rgb(170, 255, 255)
67 |
68 |
69 |
70 | -
71 |
72 |
73 | Qt::ClickFocus
74 |
75 |
76 | ...
77 |
78 |
79 |
80 |
81 |
82 | -
83 |
84 |
85 |
86 | 10
87 |
88 |
89 |
90 | Background File
91 |
92 |
93 |
94 | -
95 |
96 |
-
97 |
98 |
99 | Qt::StrongFocus
100 |
101 |
102 |
103 | -
104 |
105 |
106 | Qt::ClickFocus
107 |
108 |
109 | ...
110 |
111 |
112 |
113 |
114 |
115 | -
116 |
117 |
118 |
119 | 10
120 |
121 |
122 |
123 | Mallet Bin Directory
124 |
125 |
126 |
127 | -
128 |
129 |
-
130 |
131 |
132 | Qt::StrongFocus
133 |
134 |
135 |
136 | -
137 |
138 |
139 | Qt::ClickFocus
140 |
141 |
142 | ...
143 |
144 |
145 |
146 |
147 |
148 | -
149 |
150 |
151 |
152 | 10
153 |
154 |
155 |
156 | Group By
157 |
158 |
159 |
160 | -
161 |
162 |
-
163 |
164 | Year
165 |
166 |
167 | -
168 |
169 | Month
170 |
171 |
172 | -
173 |
174 | Quarter
175 |
176 |
177 |
178 |
179 | -
180 |
181 |
182 |
183 | 10
184 |
185 |
186 |
187 | Exploration Name
188 |
189 |
190 |
191 | -
192 |
193 |
194 | -
195 |
196 |
197 |
198 | 10
199 |
200 |
201 |
202 | Number of Ideas
203 |
204 |
205 |
206 | -
207 |
208 |
209 | -
210 |
211 |
212 |
213 | 10
214 |
215 |
216 |
217 | Tokenize
218 |
219 |
220 |
221 | -
222 |
223 |
224 |
225 |
226 |
227 |
228 | -
229 |
230 |
231 |
232 | 10
233 |
234 |
235 |
236 | Lemmatize
237 |
238 |
239 |
240 | -
241 |
242 |
243 |
244 |
245 |
246 |
247 | -
248 |
249 |
250 |
251 | 10
252 |
253 |
254 |
255 | No Stop Words
256 |
257 |
258 |
259 | -
260 |
261 |
262 |
263 |
264 |
265 |
266 | -
267 |
268 |
269 |
270 | 10
271 |
272 |
273 |
274 | Output Directory
275 |
276 |
277 |
278 | -
279 |
280 |
-
281 |
282 |
283 | Qt::StrongFocus
284 |
285 |
286 |
287 | -
288 |
289 |
290 | Qt::ClickFocus
291 |
292 |
293 | ...
294 |
295 |
296 |
297 |
298 |
299 | -
300 |
301 |
-
302 |
303 |
304 | Qt::StrongFocus
305 |
306 |
307 |
308 | -
309 |
310 |
311 | Qt::ClickFocus
312 |
313 |
314 | ...
315 |
316 |
317 |
318 |
319 |
320 | -
321 |
322 |
323 |
324 | 10
325 |
326 |
327 |
328 | Final Output Directory
329 |
330 |
331 |
332 | -
333 |
334 |
335 | Qt::Horizontal
336 |
337 |
338 |
339 | -
340 |
341 |
342 |
343 | 10
344 |
345 |
346 |
347 | Advanced Options
348 |
349 |
350 |
351 | -
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 | optionBox
362 | inputFile
363 | bckFile
364 | malletDir
365 | groupBox
366 | prefix
367 | numIdeas
368 | tokenizeBox
369 | lemmatizeBox
370 | stopwordBox
371 |
372 |
373 |
374 |
375 |
--------------------------------------------------------------------------------
/Visualizer/ui/preprocessor_run.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'preprocessor_run.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.9
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 | from PyQt5 import QtCore, QtGui, QtWidgets
10 |
11 | class Ui_preprocessorRun(object):
12 | def setupUi(self, preprocessorRun):
13 | preprocessorRun.setObjectName("preprocessorRun")
14 | preprocessorRun.resize(414, 87)
15 | self.verticalLayout = QtWidgets.QVBoxLayout(preprocessorRun)
16 | self.verticalLayout.setObjectName("verticalLayout")
17 | self.runPreprocessor = QtWidgets.QPushButton(preprocessorRun)
18 | self.runPreprocessor.setObjectName("runPreprocessor")
19 | self.verticalLayout.addWidget(self.runPreprocessor)
20 | self.progressBar = QtWidgets.QProgressBar(preprocessorRun)
21 | self.progressBar.setEnabled(False)
22 | self.progressBar.setMaximum(0)
23 | self.progressBar.setProperty("value", -1)
24 | self.progressBar.setAlignment(QtCore.Qt.AlignCenter)
25 | self.progressBar.setInvertedAppearance(False)
26 | self.progressBar.setObjectName("progressBar")
27 | self.verticalLayout.addWidget(self.progressBar)
28 |
29 | self.retranslateUi(preprocessorRun)
30 | QtCore.QMetaObject.connectSlotsByName(preprocessorRun)
31 |
32 | def retranslateUi(self, preprocessorRun):
33 | _translate = QtCore.QCoreApplication.translate
34 | preprocessorRun.setWindowTitle(_translate("preprocessorRun", "Form"))
35 | self.runPreprocessor.setText(_translate("preprocessorRun", "Run Preprocessor"))
36 |
37 |
--------------------------------------------------------------------------------
/Visualizer/ui/preprocessor_run.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | preprocessorRun
4 |
5 |
6 |
7 | 0
8 | 0
9 | 414
10 | 87
11 |
12 |
13 |
14 | Form
15 |
16 |
17 | -
18 |
19 |
20 | Run Preprocessor
21 |
22 |
23 |
24 | -
25 |
26 |
27 | false
28 |
29 |
30 | 0
31 |
32 |
33 | -1
34 |
35 |
36 | Qt::AlignCenter
37 |
38 |
39 | false
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/Visualizer/ui/relation_types.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'relation_types.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.9
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 | from PyQt5 import QtCore, QtGui, QtWidgets
10 |
11 | class Ui_relationTypes(object):
12 | def setupUi(self, relationTypes):
13 | relationTypes.setObjectName("relationTypes")
14 | relationTypes.resize(322, 451)
15 | self.verticalLayout = QtWidgets.QVBoxLayout(relationTypes)
16 | self.verticalLayout.setObjectName("verticalLayout")
17 | self.label = QtWidgets.QLabel(relationTypes)
18 | font = QtGui.QFont()
19 | font.setPointSize(12)
20 | self.label.setFont(font)
21 | self.label.setAlignment(QtCore.Qt.AlignCenter)
22 | self.label.setObjectName("label")
23 | self.verticalLayout.addWidget(self.label)
24 | self.gridLayout = QtWidgets.QGridLayout()
25 | self.gridLayout.setObjectName("gridLayout")
26 | self.friendsButton = QtWidgets.QPushButton(relationTypes)
27 | self.friendsButton.setObjectName("friendsButton")
28 | self.gridLayout.addWidget(self.friendsButton, 0, 0, 1, 1)
29 | self.trystButton = QtWidgets.QPushButton(relationTypes)
30 | self.trystButton.setObjectName("trystButton")
31 | self.gridLayout.addWidget(self.trystButton, 0, 1, 1, 1)
32 | self.headtoheadButton = QtWidgets.QPushButton(relationTypes)
33 | self.headtoheadButton.setObjectName("headtoheadButton")
34 | self.gridLayout.addWidget(self.headtoheadButton, 1, 0, 1, 1)
35 | self.armsraceButton = QtWidgets.QPushButton(relationTypes)
36 | self.armsraceButton.setObjectName("armsraceButton")
37 | self.gridLayout.addWidget(self.armsraceButton, 1, 1, 1, 1)
38 | self.verticalLayout.addLayout(self.gridLayout)
39 | self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
40 | self.horizontalLayout_2.setObjectName("horizontalLayout_2")
41 | self.friendsTable = QtWidgets.QTableWidget(relationTypes)
42 | self.friendsTable.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
43 | self.friendsTable.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
44 | self.friendsTable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
45 | self.friendsTable.setCornerButtonEnabled(False)
46 | self.friendsTable.setObjectName("friendsTable")
47 | self.friendsTable.setColumnCount(3)
48 | self.friendsTable.setRowCount(0)
49 | item = QtWidgets.QTableWidgetItem()
50 | self.friendsTable.setHorizontalHeaderItem(0, item)
51 | item = QtWidgets.QTableWidgetItem()
52 | self.friendsTable.setHorizontalHeaderItem(1, item)
53 | item = QtWidgets.QTableWidgetItem()
54 | self.friendsTable.setHorizontalHeaderItem(2, item)
55 | self.friendsTable.verticalHeader().setVisible(False)
56 | self.horizontalLayout_2.addWidget(self.friendsTable)
57 | self.armsraceTable = QtWidgets.QTableWidget(relationTypes)
58 | self.armsraceTable.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
59 | self.armsraceTable.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
60 | self.armsraceTable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
61 | self.armsraceTable.setCornerButtonEnabled(False)
62 | self.armsraceTable.setObjectName("armsraceTable")
63 | self.armsraceTable.setColumnCount(3)
64 | self.armsraceTable.setRowCount(0)
65 | item = QtWidgets.QTableWidgetItem()
66 | self.armsraceTable.setHorizontalHeaderItem(0, item)
67 | item = QtWidgets.QTableWidgetItem()
68 | self.armsraceTable.setHorizontalHeaderItem(1, item)
69 | item = QtWidgets.QTableWidgetItem()
70 | self.armsraceTable.setHorizontalHeaderItem(2, item)
71 | self.armsraceTable.verticalHeader().setVisible(False)
72 | self.horizontalLayout_2.addWidget(self.armsraceTable)
73 | self.headtoheadTable = QtWidgets.QTableWidget(relationTypes)
74 | self.headtoheadTable.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
75 | self.headtoheadTable.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
76 | self.headtoheadTable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
77 | self.headtoheadTable.setCornerButtonEnabled(False)
78 | self.headtoheadTable.setObjectName("headtoheadTable")
79 | self.headtoheadTable.setColumnCount(3)
80 | self.headtoheadTable.setRowCount(0)
81 | item = QtWidgets.QTableWidgetItem()
82 | self.headtoheadTable.setHorizontalHeaderItem(0, item)
83 | item = QtWidgets.QTableWidgetItem()
84 | self.headtoheadTable.setHorizontalHeaderItem(1, item)
85 | item = QtWidgets.QTableWidgetItem()
86 | self.headtoheadTable.setHorizontalHeaderItem(2, item)
87 | self.headtoheadTable.verticalHeader().setVisible(False)
88 | self.horizontalLayout_2.addWidget(self.headtoheadTable)
89 | self.trystTable = QtWidgets.QTableWidget(relationTypes)
90 | self.trystTable.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
91 | self.trystTable.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
92 | self.trystTable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
93 | self.trystTable.setCornerButtonEnabled(False)
94 | self.trystTable.setObjectName("trystTable")
95 | self.trystTable.setColumnCount(3)
96 | self.trystTable.setRowCount(0)
97 | item = QtWidgets.QTableWidgetItem()
98 | self.trystTable.setHorizontalHeaderItem(0, item)
99 | item = QtWidgets.QTableWidgetItem()
100 | self.trystTable.setHorizontalHeaderItem(1, item)
101 | item = QtWidgets.QTableWidgetItem()
102 | self.trystTable.setHorizontalHeaderItem(2, item)
103 | self.trystTable.verticalHeader().setVisible(False)
104 | self.horizontalLayout_2.addWidget(self.trystTable)
105 | self.verticalLayout.addLayout(self.horizontalLayout_2)
106 |
107 | self.retranslateUi(relationTypes)
108 | QtCore.QMetaObject.connectSlotsByName(relationTypes)
109 |
110 | def retranslateUi(self, relationTypes):
111 | _translate = QtCore.QCoreApplication.translate
112 | relationTypes.setWindowTitle(_translate("relationTypes", "Form"))
113 | self.label.setText(_translate("relationTypes", "Top Relations"))
114 | self.friendsButton.setText(_translate("relationTypes", "Friends"))
115 | self.trystButton.setText(_translate("relationTypes", "Tryst"))
116 | self.headtoheadButton.setText(_translate("relationTypes", "Head-To-Head"))
117 | self.armsraceButton.setText(_translate("relationTypes", "Arms-Race"))
118 | item = self.friendsTable.horizontalHeaderItem(0)
119 | item.setText(_translate("relationTypes", "Strength"))
120 | item = self.friendsTable.horizontalHeaderItem(1)
121 | item.setText(_translate("relationTypes", "Relation 1"))
122 | item = self.friendsTable.horizontalHeaderItem(2)
123 | item.setText(_translate("relationTypes", "Relation 2"))
124 | item = self.armsraceTable.horizontalHeaderItem(0)
125 | item.setText(_translate("relationTypes", "Strength"))
126 | item = self.armsraceTable.horizontalHeaderItem(1)
127 | item.setText(_translate("relationTypes", "Relation 1"))
128 | item = self.armsraceTable.horizontalHeaderItem(2)
129 | item.setText(_translate("relationTypes", "Relation 2"))
130 | item = self.headtoheadTable.horizontalHeaderItem(0)
131 | item.setText(_translate("relationTypes", "Strength"))
132 | item = self.headtoheadTable.horizontalHeaderItem(1)
133 | item.setText(_translate("relationTypes", "Relation 1"))
134 | item = self.headtoheadTable.horizontalHeaderItem(2)
135 | item.setText(_translate("relationTypes", "Relation 2"))
136 | item = self.trystTable.horizontalHeaderItem(0)
137 | item.setText(_translate("relationTypes", "Strength"))
138 | item = self.trystTable.horizontalHeaderItem(1)
139 | item.setText(_translate("relationTypes", "Relation 1"))
140 | item = self.trystTable.horizontalHeaderItem(2)
141 | item.setText(_translate("relationTypes", "Relation 2"))
142 |
143 |
--------------------------------------------------------------------------------
/Visualizer/ui/relation_types.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | relationTypes
4 |
5 |
6 |
7 | 0
8 | 0
9 | 322
10 | 451
11 |
12 |
13 |
14 | Form
15 |
16 |
17 | -
18 |
19 |
20 |
21 | 12
22 |
23 |
24 |
25 | Top Relations
26 |
27 |
28 | Qt::AlignCenter
29 |
30 |
31 |
32 | -
33 |
34 |
-
35 |
36 |
37 | Friends
38 |
39 |
40 |
41 | -
42 |
43 |
44 | Tryst
45 |
46 |
47 |
48 | -
49 |
50 |
51 | Head-To-Head
52 |
53 |
54 |
55 | -
56 |
57 |
58 | Arms-Race
59 |
60 |
61 |
62 |
63 |
64 | -
65 |
66 |
-
67 |
68 |
69 | QAbstractItemView::NoEditTriggers
70 |
71 |
72 | QAbstractItemView::SingleSelection
73 |
74 |
75 | QAbstractItemView::SelectRows
76 |
77 |
78 | false
79 |
80 |
81 | false
82 |
83 |
84 |
85 | Strength
86 |
87 |
88 |
89 |
90 | Relation 1
91 |
92 |
93 |
94 |
95 | Relation 2
96 |
97 |
98 |
99 |
100 | -
101 |
102 |
103 | QAbstractItemView::NoEditTriggers
104 |
105 |
106 | QAbstractItemView::SingleSelection
107 |
108 |
109 | QAbstractItemView::SelectRows
110 |
111 |
112 | false
113 |
114 |
115 | false
116 |
117 |
118 |
119 | Strength
120 |
121 |
122 |
123 |
124 | Relation 1
125 |
126 |
127 |
128 |
129 | Relation 2
130 |
131 |
132 |
133 |
134 | -
135 |
136 |
137 | QAbstractItemView::NoEditTriggers
138 |
139 |
140 | QAbstractItemView::SingleSelection
141 |
142 |
143 | QAbstractItemView::SelectRows
144 |
145 |
146 | false
147 |
148 |
149 | false
150 |
151 |
152 |
153 | Strength
154 |
155 |
156 |
157 |
158 | Relation 1
159 |
160 |
161 |
162 |
163 | Relation 2
164 |
165 |
166 |
167 |
168 | -
169 |
170 |
171 | QAbstractItemView::NoEditTriggers
172 |
173 |
174 | QAbstractItemView::SingleSelection
175 |
176 |
177 | QAbstractItemView::SelectRows
178 |
179 |
180 | false
181 |
182 |
183 | false
184 |
185 |
186 |
187 | Strength
188 |
189 |
190 |
191 |
192 | Relation 1
193 |
194 |
195 |
196 |
197 | Relation 2
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
--------------------------------------------------------------------------------
/Visualizer/ui/relation_types_tabs.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'relation_types_tabs.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.9
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 | from PyQt5 import QtCore, QtGui, QtWidgets
10 |
11 | class Ui_relationTypes(object):
12 | def setupUi(self, relationTypes):
13 | relationTypes.setObjectName("relationTypes")
14 | relationTypes.setEnabled(True)
15 | relationTypes.resize(494, 373)
16 | self.verticalLayout = QtWidgets.QVBoxLayout(relationTypes)
17 | self.verticalLayout.setObjectName("verticalLayout")
18 | self.label = QtWidgets.QLabel(relationTypes)
19 | font = QtGui.QFont()
20 | font.setPointSize(12)
21 | self.label.setFont(font)
22 | self.label.setAlignment(QtCore.Qt.AlignCenter)
23 | self.label.setObjectName("label")
24 | self.verticalLayout.addWidget(self.label)
25 | self.tabWidget = QtWidgets.QTabWidget(relationTypes)
26 | self.tabWidget.setAutoFillBackground(True)
27 | self.tabWidget.setStyleSheet("QTabBar::tab:selected { text-decoration: underline; }")
28 | self.tabWidget.setTabPosition(QtWidgets.QTabWidget.North)
29 | self.tabWidget.setTabShape(QtWidgets.QTabWidget.Rounded)
30 | self.tabWidget.setObjectName("tabWidget")
31 | self.friendsTab = QtWidgets.QWidget()
32 | self.friendsTab.setObjectName("friendsTab")
33 | self.horizontalLayout = QtWidgets.QHBoxLayout(self.friendsTab)
34 | self.horizontalLayout.setObjectName("horizontalLayout")
35 | self.friendsTable = QtWidgets.QTableWidget(self.friendsTab)
36 | self.friendsTable.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
37 | self.friendsTable.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
38 | self.friendsTable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
39 | self.friendsTable.setCornerButtonEnabled(False)
40 | self.friendsTable.setObjectName("friendsTable")
41 | self.friendsTable.setColumnCount(3)
42 | self.friendsTable.setRowCount(0)
43 | item = QtWidgets.QTableWidgetItem()
44 | self.friendsTable.setHorizontalHeaderItem(0, item)
45 | item = QtWidgets.QTableWidgetItem()
46 | self.friendsTable.setHorizontalHeaderItem(1, item)
47 | item = QtWidgets.QTableWidgetItem()
48 | self.friendsTable.setHorizontalHeaderItem(2, item)
49 | self.friendsTable.verticalHeader().setVisible(False)
50 | self.horizontalLayout.addWidget(self.friendsTable)
51 | self.tabWidget.addTab(self.friendsTab, "")
52 | self.trystTab = QtWidgets.QWidget()
53 | self.trystTab.setObjectName("trystTab")
54 | self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.trystTab)
55 | self.horizontalLayout_2.setObjectName("horizontalLayout_2")
56 | self.trystTable = QtWidgets.QTableWidget(self.trystTab)
57 | self.trystTable.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
58 | self.trystTable.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
59 | self.trystTable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
60 | self.trystTable.setCornerButtonEnabled(False)
61 | self.trystTable.setObjectName("trystTable")
62 | self.trystTable.setColumnCount(3)
63 | self.trystTable.setRowCount(0)
64 | item = QtWidgets.QTableWidgetItem()
65 | self.trystTable.setHorizontalHeaderItem(0, item)
66 | item = QtWidgets.QTableWidgetItem()
67 | self.trystTable.setHorizontalHeaderItem(1, item)
68 | item = QtWidgets.QTableWidgetItem()
69 | self.trystTable.setHorizontalHeaderItem(2, item)
70 | self.trystTable.verticalHeader().setVisible(False)
71 | self.horizontalLayout_2.addWidget(self.trystTable)
72 | self.tabWidget.addTab(self.trystTab, "")
73 | self.headtoheadTab = QtWidgets.QWidget()
74 | self.headtoheadTab.setObjectName("headtoheadTab")
75 | self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.headtoheadTab)
76 | self.horizontalLayout_3.setObjectName("horizontalLayout_3")
77 | self.headtoheadTable = QtWidgets.QTableWidget(self.headtoheadTab)
78 | self.headtoheadTable.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
79 | self.headtoheadTable.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
80 | self.headtoheadTable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
81 | self.headtoheadTable.setCornerButtonEnabled(False)
82 | self.headtoheadTable.setObjectName("headtoheadTable")
83 | self.headtoheadTable.setColumnCount(3)
84 | self.headtoheadTable.setRowCount(0)
85 | item = QtWidgets.QTableWidgetItem()
86 | self.headtoheadTable.setHorizontalHeaderItem(0, item)
87 | item = QtWidgets.QTableWidgetItem()
88 | self.headtoheadTable.setHorizontalHeaderItem(1, item)
89 | item = QtWidgets.QTableWidgetItem()
90 | self.headtoheadTable.setHorizontalHeaderItem(2, item)
91 | self.headtoheadTable.verticalHeader().setVisible(False)
92 | self.horizontalLayout_3.addWidget(self.headtoheadTable)
93 | self.tabWidget.addTab(self.headtoheadTab, "")
94 | self.armsraceTab = QtWidgets.QWidget()
95 | self.armsraceTab.setObjectName("armsraceTab")
96 | self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.armsraceTab)
97 | self.horizontalLayout_4.setObjectName("horizontalLayout_4")
98 | self.armsraceTable = QtWidgets.QTableWidget(self.armsraceTab)
99 | self.armsraceTable.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
100 | self.armsraceTable.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
101 | self.armsraceTable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
102 | self.armsraceTable.setCornerButtonEnabled(False)
103 | self.armsraceTable.setObjectName("armsraceTable")
104 | self.armsraceTable.setColumnCount(3)
105 | self.armsraceTable.setRowCount(0)
106 | item = QtWidgets.QTableWidgetItem()
107 | self.armsraceTable.setHorizontalHeaderItem(0, item)
108 | item = QtWidgets.QTableWidgetItem()
109 | self.armsraceTable.setHorizontalHeaderItem(1, item)
110 | item = QtWidgets.QTableWidgetItem()
111 | self.armsraceTable.setHorizontalHeaderItem(2, item)
112 | self.armsraceTable.verticalHeader().setVisible(False)
113 | self.horizontalLayout_4.addWidget(self.armsraceTable)
114 | self.tabWidget.addTab(self.armsraceTab, "")
115 | self.verticalLayout.addWidget(self.tabWidget)
116 |
117 | self.retranslateUi(relationTypes)
118 | self.tabWidget.setCurrentIndex(0)
119 | QtCore.QMetaObject.connectSlotsByName(relationTypes)
120 |
121 | def retranslateUi(self, relationTypes):
122 | _translate = QtCore.QCoreApplication.translate
123 | relationTypes.setWindowTitle(_translate("relationTypes", "Form"))
124 | self.label.setText(_translate("relationTypes", "Top Relations"))
125 | item = self.friendsTable.horizontalHeaderItem(0)
126 | item.setText(_translate("relationTypes", "Strength"))
127 | item = self.friendsTable.horizontalHeaderItem(1)
128 | item.setText(_translate("relationTypes", "Relation 1"))
129 | item = self.friendsTable.horizontalHeaderItem(2)
130 | item.setText(_translate("relationTypes", "Relation 2"))
131 | self.tabWidget.setTabText(self.tabWidget.indexOf(self.friendsTab), _translate("relationTypes", "Friends"))
132 | item = self.trystTable.horizontalHeaderItem(0)
133 | item.setText(_translate("relationTypes", "Strength"))
134 | item = self.trystTable.horizontalHeaderItem(1)
135 | item.setText(_translate("relationTypes", "Relation 1"))
136 | item = self.trystTable.horizontalHeaderItem(2)
137 | item.setText(_translate("relationTypes", "Relation 2"))
138 | self.tabWidget.setTabText(self.tabWidget.indexOf(self.trystTab), _translate("relationTypes", "Tryst"))
139 | item = self.headtoheadTable.horizontalHeaderItem(0)
140 | item.setText(_translate("relationTypes", "Strength"))
141 | item = self.headtoheadTable.horizontalHeaderItem(1)
142 | item.setText(_translate("relationTypes", "Relation 1"))
143 | item = self.headtoheadTable.horizontalHeaderItem(2)
144 | item.setText(_translate("relationTypes", "Relation 2"))
145 | self.tabWidget.setTabText(self.tabWidget.indexOf(self.headtoheadTab), _translate("relationTypes", "Head-To-Head"))
146 | item = self.armsraceTable.horizontalHeaderItem(0)
147 | item.setText(_translate("relationTypes", "Strength"))
148 | item = self.armsraceTable.horizontalHeaderItem(1)
149 | item.setText(_translate("relationTypes", "Relation 1"))
150 | item = self.armsraceTable.horizontalHeaderItem(2)
151 | item.setText(_translate("relationTypes", "Relation 2"))
152 | self.tabWidget.setTabText(self.tabWidget.indexOf(self.armsraceTab), _translate("relationTypes", "Arms-Race"))
153 |
154 |
--------------------------------------------------------------------------------
/Visualizer/ui/relation_types_tabs.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | relationTypes
4 |
5 |
6 | true
7 |
8 |
9 |
10 | 0
11 | 0
12 | 494
13 | 373
14 |
15 |
16 |
17 | Form
18 |
19 |
20 | -
21 |
22 |
23 |
24 | 12
25 |
26 |
27 |
28 | Top Relations
29 |
30 |
31 | Qt::AlignCenter
32 |
33 |
34 |
35 | -
36 |
37 |
38 | true
39 |
40 |
41 | QTabBar::tab:selected { text-decoration: underline; }
42 |
43 |
44 | QTabWidget::North
45 |
46 |
47 | QTabWidget::Rounded
48 |
49 |
50 | 0
51 |
52 |
53 |
54 | Friends
55 |
56 |
57 |
-
58 |
59 |
60 | QAbstractItemView::NoEditTriggers
61 |
62 |
63 | QAbstractItemView::SingleSelection
64 |
65 |
66 | QAbstractItemView::SelectRows
67 |
68 |
69 | false
70 |
71 |
72 | false
73 |
74 |
75 |
76 | Strength
77 |
78 |
79 |
80 |
81 | Relation 1
82 |
83 |
84 |
85 |
86 | Relation 2
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 | Tryst
96 |
97 |
98 | -
99 |
100 |
101 | QAbstractItemView::NoEditTriggers
102 |
103 |
104 | QAbstractItemView::SingleSelection
105 |
106 |
107 | QAbstractItemView::SelectRows
108 |
109 |
110 | false
111 |
112 |
113 | false
114 |
115 |
116 |
117 | Strength
118 |
119 |
120 |
121 |
122 | Relation 1
123 |
124 |
125 |
126 |
127 | Relation 2
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 | Head-To-Head
137 |
138 |
139 | -
140 |
141 |
142 | QAbstractItemView::NoEditTriggers
143 |
144 |
145 | QAbstractItemView::SingleSelection
146 |
147 |
148 | QAbstractItemView::SelectRows
149 |
150 |
151 | false
152 |
153 |
154 | false
155 |
156 |
157 |
158 | Strength
159 |
160 |
161 |
162 |
163 | Relation 1
164 |
165 |
166 |
167 |
168 | Relation 2
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 | Arms-Race
178 |
179 |
180 | -
181 |
182 |
183 | QAbstractItemView::NoEditTriggers
184 |
185 |
186 | QAbstractItemView::SingleSelection
187 |
188 |
189 | QAbstractItemView::SelectRows
190 |
191 |
192 | false
193 |
194 |
195 | false
196 |
197 |
198 |
199 | Strength
200 |
201 |
202 |
203 |
204 | Relation 1
205 |
206 |
207 |
208 |
209 | Relation 2
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
--------------------------------------------------------------------------------
/Visualizer/ui/top_relations.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'top_relations.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.9
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 | from PyQt5 import QtCore, QtGui, QtWidgets
10 |
11 | class Ui_topRelation(object):
12 | def setupUi(self, topRelation):
13 | topRelation.setObjectName("topRelation")
14 | topRelation.resize(324, 300)
15 | self.verticalLayout = QtWidgets.QVBoxLayout(topRelation)
16 | self.verticalLayout.setObjectName("verticalLayout")
17 | self.horizontalLayout = QtWidgets.QHBoxLayout()
18 | self.horizontalLayout.setObjectName("horizontalLayout")
19 | self.staticLabel = QtWidgets.QLabel(topRelation)
20 | font = QtGui.QFont()
21 | font.setPointSize(12)
22 | self.staticLabel.setFont(font)
23 | self.staticLabel.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
24 | self.staticLabel.setObjectName("staticLabel")
25 | self.horizontalLayout.addWidget(self.staticLabel)
26 | self.relationName = QtWidgets.QLabel(topRelation)
27 | font = QtGui.QFont()
28 | font.setPointSize(12)
29 | self.relationName.setFont(font)
30 | self.relationName.setText("")
31 | self.relationName.setScaledContents(False)
32 | self.relationName.setObjectName("relationName")
33 | self.horizontalLayout.addWidget(self.relationName)
34 | self.verticalLayout.addLayout(self.horizontalLayout)
35 | self.tableWidget = QtWidgets.QTableWidget(topRelation)
36 | self.tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
37 | self.tableWidget.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
38 | self.tableWidget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
39 | self.tableWidget.setObjectName("tableWidget")
40 | self.tableWidget.setColumnCount(3)
41 | self.tableWidget.setRowCount(0)
42 | item = QtWidgets.QTableWidgetItem()
43 | self.tableWidget.setHorizontalHeaderItem(0, item)
44 | item = QtWidgets.QTableWidgetItem()
45 | self.tableWidget.setHorizontalHeaderItem(1, item)
46 | item = QtWidgets.QTableWidgetItem()
47 | self.tableWidget.setHorizontalHeaderItem(2, item)
48 | self.tableWidget.verticalHeader().setVisible(False)
49 | self.verticalLayout.addWidget(self.tableWidget)
50 |
51 | self.retranslateUi(topRelation)
52 | QtCore.QMetaObject.connectSlotsByName(topRelation)
53 |
54 | def retranslateUi(self, topRelation):
55 | _translate = QtCore.QCoreApplication.translate
56 | topRelation.setWindowTitle(_translate("topRelation", "Form"))
57 | self.staticLabel.setText(_translate("topRelation", "Selected Relation:"))
58 | item = self.tableWidget.horizontalHeaderItem(0)
59 | item.setText(_translate("topRelation", "Strength"))
60 | item = self.tableWidget.horizontalHeaderItem(1)
61 | item.setText(_translate("topRelation", "Relation Type"))
62 | item = self.tableWidget.horizontalHeaderItem(2)
63 | item.setText(_translate("topRelation", "Relation 2"))
64 |
65 |
--------------------------------------------------------------------------------
/Visualizer/ui/top_relations.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | topRelation
4 |
5 |
6 |
7 | 0
8 | 0
9 | 324
10 | 300
11 |
12 |
13 |
14 | Form
15 |
16 |
17 | -
18 |
19 |
-
20 |
21 |
22 |
23 | 12
24 |
25 |
26 |
27 | Selected Relation:
28 |
29 |
30 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
31 |
32 |
33 |
34 | -
35 |
36 |
37 |
38 | 12
39 |
40 |
41 |
42 |
43 |
44 |
45 | false
46 |
47 |
48 |
49 |
50 |
51 | -
52 |
53 |
54 | QAbstractItemView::NoEditTriggers
55 |
56 |
57 | QAbstractItemView::SingleSelection
58 |
59 |
60 | QAbstractItemView::SelectRows
61 |
62 |
63 | false
64 |
65 |
66 |
67 | Strength
68 |
69 |
70 |
71 |
72 | Relation Type
73 |
74 |
75 |
76 |
77 | Relation 2
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/Visualizer/ui/topics_list.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'topics_list.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.9
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 | from PyQt5 import QtCore, QtGui, QtWidgets
10 |
11 | class Ui_topicsList(object):
12 | def setupUi(self, topicsList):
13 | topicsList.setObjectName("topicsList")
14 | topicsList.resize(642, 730)
15 | self.verticalLayout = QtWidgets.QVBoxLayout(topicsList)
16 | self.verticalLayout.setObjectName("verticalLayout")
17 | self.label = QtWidgets.QLabel(topicsList)
18 | font = QtGui.QFont()
19 | font.setPointSize(12)
20 | self.label.setFont(font)
21 | self.label.setAlignment(QtCore.Qt.AlignCenter)
22 | self.label.setObjectName("label")
23 | self.verticalLayout.addWidget(self.label)
24 | self.filterText = QtWidgets.QLineEdit(topicsList)
25 | self.filterText.setObjectName("filterText")
26 | self.verticalLayout.addWidget(self.filterText)
27 | self.listWidget = QtWidgets.QListView(topicsList)
28 | self.listWidget.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
29 | self.listWidget.setObjectName("listWidget")
30 | self.verticalLayout.addWidget(self.listWidget)
31 |
32 | self.retranslateUi(topicsList)
33 | QtCore.QMetaObject.connectSlotsByName(topicsList)
34 |
35 | def retranslateUi(self, topicsList):
36 | _translate = QtCore.QCoreApplication.translate
37 | topicsList.setWindowTitle(_translate("topicsList", "Form"))
38 | self.label.setText(_translate("topicsList", "Topics"))
39 | self.filterText.setPlaceholderText(_translate("topicsList", "Filter Topics"))
40 |
41 |
--------------------------------------------------------------------------------
/Visualizer/ui/topics_list.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | topicsList
4 |
5 |
6 |
7 | 0
8 | 0
9 | 642
10 | 730
11 |
12 |
13 |
14 | Form
15 |
16 |
17 | -
18 |
19 |
20 |
21 | 12
22 |
23 |
24 |
25 | Topics
26 |
27 |
28 | Qt::AlignCenter
29 |
30 |
31 |
32 | -
33 |
34 |
35 | Filter Topics
36 |
37 |
38 |
39 | -
40 |
41 |
42 | QAbstractItemView::ExtendedSelection
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/Visualizer/ui/visualizer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'visualizer.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.9
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 | from PyQt5 import QtCore, QtGui, QtWidgets
10 |
11 | class Ui_visualizaerWidget(object):
12 | def setupUi(self, visualizaerWidget):
13 | visualizaerWidget.setObjectName("visualizaerWidget")
14 | visualizaerWidget.resize(1024, 657)
15 | self.horizontalLayout = QtWidgets.QHBoxLayout(visualizaerWidget)
16 | self.horizontalLayout.setObjectName("horizontalLayout")
17 | self.tabWidget = QtWidgets.QTabWidget(visualizaerWidget)
18 | self.tabWidget.setMinimumSize(QtCore.QSize(0, 0))
19 | self.tabWidget.setMaximumSize(QtCore.QSize(400, 16777215))
20 | self.tabWidget.setTabPosition(QtWidgets.QTabWidget.South)
21 | self.tabWidget.setObjectName("tabWidget")
22 | self.horizontalLayout.addWidget(self.tabWidget)
23 | self.pmiWidget = QtWidgets.QWidget(visualizaerWidget)
24 | self.pmiWidget.setObjectName("pmiWidget")
25 | self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.pmiWidget)
26 | self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0)
27 | self.horizontalLayout_4.setObjectName("horizontalLayout_4")
28 | self.horizontalLayout.addWidget(self.pmiWidget)
29 | self.tsWidget = QtWidgets.QWidget(visualizaerWidget)
30 | self.tsWidget.setObjectName("tsWidget")
31 | self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.tsWidget)
32 | self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
33 | self.horizontalLayout_2.setObjectName("horizontalLayout_2")
34 | self.horizontalLayout.addWidget(self.tsWidget)
35 |
36 | self.retranslateUi(visualizaerWidget)
37 | QtCore.QMetaObject.connectSlotsByName(visualizaerWidget)
38 |
39 | def retranslateUi(self, visualizaerWidget):
40 | _translate = QtCore.QCoreApplication.translate
41 | visualizaerWidget.setWindowTitle(_translate("visualizaerWidget", "Form"))
42 |
43 |
--------------------------------------------------------------------------------
/Visualizer/ui/visualizer.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | visualizaerWidget
4 |
5 |
6 |
7 | 0
8 | 0
9 | 1024
10 | 657
11 |
12 |
13 |
14 | Form
15 |
16 |
17 | -
18 |
19 |
20 |
21 | 0
22 | 0
23 |
24 |
25 |
26 |
27 | 400
28 | 16777215
29 |
30 |
31 |
32 | QTabWidget::South
33 |
34 |
35 |
36 | -
37 |
38 |
39 |
40 |
41 | -
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/Visualizer/widgets/ColoredBox.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 7/6/2017
3 |
4 | import random
5 |
6 | import tkinter as tk
7 |
8 |
9 | used_colors = set()
10 | def get_color():
11 | r = random.randint(0, 255)
12 | g = random.randint(0, 255)
13 | b = random.randint(0, 255)
14 |
15 | color = "#{:02x}{:02x}{:02x}".format(r, g, b)
16 |
17 | if color not in used_colors:
18 | used_colors.add(color)
19 | return color
20 | else:
21 | return get_color()
22 |
23 | class ColoredBox(object):
24 | """
25 | Randomly colored frame
26 | Default width/height of 100
27 | """
28 |
29 | def __init__(self, master, width=100, height=100):
30 | self.frame = tk.Frame(master=master, background=get_color(), width=width, height=height)
31 |
32 | def pack(self, **kwargs):
33 | self.frame.pack(**kwargs)
34 |
35 | def grid(self, **kwargs):
36 | self.frame.grid(**kwargs)
37 |
38 | def set_color(self, color):
39 | self.frame.configure(background=color)
40 |
41 | if __name__ == "__main__":
42 | root = tk.Tk()
43 | box = ColoredBox(root)
44 | box.pack(fill=tk.X)
45 |
46 | root.mainloop()
47 |
48 |
--------------------------------------------------------------------------------
/Visualizer/widgets/ListBoxColumn.py:
--------------------------------------------------------------------------------
1 | # Nikko Rush
2 | # 7/8/2017
3 |
4 | import functools
5 | import sys
6 |
7 | windows, linux, osx = False, False, False
8 | if sys.platform == 'win32':
9 | windows = True
10 | elif sys.platform == 'linux':
11 | linux = True # Assume that a display exists, cause if one doesn't exist you should have crashed a long time ago
12 | elif sys.platform == 'darwin':
13 | osx = True
14 | else:
15 | print("Error: Unknown system platform type")
16 |
17 | import tkinter as tk
18 |
19 | class ListBoxColumn(tk.Frame):
20 | """Works more or less like a listbox, but with columns"""
21 | def __init__(self, ncolumns=1, master=None, cnf={}, listboxkwargs={}, **kw):
22 | super(ListBoxColumn, self).__init__(master=master, cnf=cnf, **kw);
23 |
24 | self.list = tk.Listbox()
25 |
26 | self.ncolumns = ncolumns
27 | self.lists = [tk.Listbox(self, exportselection=False, **listboxkwargs) for i in range(ncolumns)]
28 |
29 | for listBox in self.lists:
30 | listBox.pack(side=tk.LEFT, fill=tk.Y, expand=1)
31 |
32 | listBox.bind("<>", self._on_select)
33 | if windows or osx:
34 | listBox.bind("", self._yscroll)
35 | else:
36 | listBox.bind("", functools.partial(self._yscroll, direction=-1))
37 | listBox.bind("", functools.partial(self._yscroll, direction=1))
38 |
39 |
40 | self.xscrollbar = tk.Scrollbar(self, orient=tk.VERTICAL)
41 | self.lists[0].config(xscrollcommand=self.xscrollbar.set)
42 | self.xscrollbar.config(command=self._xscroll)
43 |
44 | self.yscrollbar = tk.Scrollbar(self, orient=tk.VERTICAL)
45 | self.lists[0].config(yscrollcommand=self.yscrollbar.set)
46 | self.yscrollbar.config(command=self._yscroll)
47 |
48 | self.select_handlers = list()
49 |
50 | self.add_select_handler(self._sync_selection)
51 |
52 | def show_xscrollbar(self):
53 | self.xscrollbar.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=1)
54 |
55 | def show_yscrollbar(self):
56 | self.yscrollbar.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
57 |
58 | def hide_xscrollbar(self):
59 | self._remove_scrollbar(self.xscrollbar)
60 |
61 | def hide_yscrollbar(self):
62 | self._remove_scrollbar(self.yscrollbar)
63 |
64 | def _remove_scrollbar(self, scrollbar):
65 | scrollbar.pack_forget()
66 |
67 |
68 | def activate(self, index):
69 | for listBox in self.lists:
70 | listBox.activate(index)
71 |
72 | def bbox(self, index):
73 | raise NotImplementedError
74 |
75 | def config(self, **options):
76 | for listBox in self.lists:
77 | listBox.config(**options)
78 |
79 | def curselection(self):
80 | return self.lists[0].curselection()
81 |
82 | def delete(self, first, last=None):
83 | for listBox in self.lists:
84 | listBox.delete(first, last)
85 |
86 | def get(self, first, last=None):
87 | for listBox in self.lists:
88 | listBox.get(first, last)
89 |
90 | def index(self, index):
91 | return self.lists[0].index(index)
92 |
93 | def insert(self, index, *elements):
94 | """
95 | Elements should be an iterable with atleast self.ncolumns items
96 | If an element that you try to add has fewer than self.ncolumns items it will be padded with empty strings
97 | """
98 | for element in elements:
99 | adding = list(element) + [' '] * (self.ncolumns - len(element))
100 | for item, listBox in zip(adding, self.lists):
101 | listBox.insert(index, item)
102 |
103 | def delete(self, first, last=None):
104 | for list in self.lists:
105 | list.delete(first, last)
106 |
107 | def itemcget(self, index, option):
108 | return self.lists[0].itemcget(index, option)
109 |
110 | def nearest(self, y):
111 | return self.lists[0].nearest(y)
112 |
113 | def scan_dragto(self, x, y):
114 | raise NotImplementedError
115 |
116 | def see(self, index):
117 | for listBox in self.lists:
118 | listBox.see(index)
119 |
120 | def selection_anchor(self, index):
121 | for listBox in self.lists:
122 | listBox.select_anchor(index)
123 |
124 | def selection_clear(self, first, last=None):
125 | for listBox in self.lists:
126 | listBox.select_clear(first, last)
127 |
128 | def selection_includes(self, index):
129 | return self.lists[0].select_includes(index)
130 |
131 | def selection_set(self, first, last=None):
132 | for listBox in self.lists:
133 | listBox.select_set(first, last)
134 |
135 | select_anchor = selection_anchor
136 | select_clear = selection_clear
137 | select_includes = selection_includes
138 | select_set = selection_set
139 |
140 | def size(self):
141 | return self.lists[0].size()
142 |
143 | def xview(self, column, *extra):
144 | for listBox in self.lists:
145 | listBox.xview(column, *extra)
146 |
147 | def xview_moveto(self, fraction):
148 | for listBox in self.lists:
149 | listBox.xview_moveto(fraction)
150 |
151 | def xview_scroll(self, number, what):
152 | for listBox in self.lists:
153 | listBox.xview_scroll(number, what)
154 | return "break"
155 |
156 | def yview(self, *what):
157 | print("YView: " + str(what))
158 | for listBox in self.lists:
159 | listBox.yview(*what)
160 |
161 | def yview_moveto(self, fraction):
162 | for listBox in self.lists:
163 | listBox.yview_moveto(fraction)
164 |
165 | def yview_scroll(self, number, what):
166 | for listBox in self.lists:
167 | listBox.yview_scroll(number, what)
168 | return "break"
169 |
170 | def bind(self, sequence=None, func=None, add=None):
171 | def handler(event):
172 | event.ListBoxColumn = self
173 | func(event)
174 |
175 | for listBox in self.lists:
176 | listBox.bind(sequence, handler)
177 |
178 | def add_select_handler(self, handler):
179 | self.select_handlers.append(handler)
180 |
181 | def remove_select_handler(self, handler):
182 | self.select_handlers.remove(handler)
183 |
184 | def _on_select(self, event):
185 | for func in self.select_handlers:
186 | event.ListBoxColumn = self
187 | func(event)
188 |
189 | def _sync_selection(self, event):
190 | selected = event.widget.curselection()
191 |
192 | self.select_clear(0, tk.END)
193 | for index in selected:
194 | self.select_set(index)
195 |
196 | def set_width(self):
197 | for listBox in self.lists:
198 | self._update_width(listBox)
199 |
200 | def _update_width(self, listBox):
201 | max_width = -1
202 | for item in listBox.get(0, tk.END):
203 | if len(str(item)) > max_width:
204 | max_width = len(str(item))
205 |
206 | listBox.config(width=max_width)
207 |
208 | def _tmp(self, *args):
209 | return self._yscroll(args[0])
210 |
211 | def _yscroll(self, event, direction=None):
212 | if windows:
213 | return self.yview_scroll(int(event.delta / -120), "units")
214 | elif linux:
215 | return self.yview_scroll(direction, "units")
216 | elif osx:
217 | return self.yview_scroll(int(event.delta), "units")
218 |
219 |
220 | def _xscroll(self, event):
221 | return self.xview_scroll(int(event.delta/-120), "units")
--------------------------------------------------------------------------------
/Visualizer/widgets/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nwrush/Visualization/bc134aa02156956ea3644b34d491da9f0e9f63ae/Visualizer/widgets/__init__.py
--------------------------------------------------------------------------------
/examples/acl.jsonlist.gz:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:c5a150926e109703bd963c5ef152e772e629aa833b55a731a6e2f8c4c5674b92
3 | size 55069109
4 |
--------------------------------------------------------------------------------
/examples/acl.p:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nwrush/Visualization/bc134aa02156956ea3644b34d491da9f0e9f63ae/examples/acl.p
--------------------------------------------------------------------------------
/examples/nips.jsonlist.gz:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:7b95da8a5cd76a734a33daca528f76f6f0ba77e7f956c8446944125969e2b2e8
3 | size 61624904
4 |
--------------------------------------------------------------------------------
/examples/nips_t.p:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nwrush/Visualization/bc134aa02156956ea3644b34d491da9f0e9f63ae/examples/nips_t.p
--------------------------------------------------------------------------------