GithubHelp home page GithubHelp logo

timwis / vizwit Goto Github PK

View Code? Open in Web Editor NEW
100.0 11.0 36.0 12.25 MB

An interactive data visualization tool

Home Page: http://vizwit.io

License: GNU General Public License v2.0

JavaScript 84.10% HTML 12.41% CSS 3.07% Shell 0.43%

vizwit's Introduction

VizWit

Join the chat at https://gitter.im/timwis/vizwit Stories in Ready Build Status js-standard-style

An interactive data visualization tool. VizWit uses a JSON config file to generate interactive charts that cross-filter one another. It currently supports data hosted in Socrata and Carto, which includes open data provided by cities such as Philadelphia, Chicago, and San Francisco). Data that’s hosted elsewhere can be supported by adding a new data provider.

screencast

Features

  • Clicking on a chart cross-filters the other charts
  • Multiple datasets on one page
  • Configurable via GUI (work in progress)
  • Fork configurations with a gist
  • Pie chart
  • Callout metric
  • Scrolling bar charts
  • Responsive / mobile-friendly
  • Embeddable (and cross-filtering still works)
  • Free-text search on table
  • 100% client-side
  • Open source / extendable

Examples

Configuration

VizWit cards are configured via JSON objects. The layout is defined using size and order properties on those objects, generated by the Config Builder (work in progress). The resulting JSON file is then hosted on gist.github.com, a free and easy service to share code snippets. The Gist ID is then used in the VizWit URL (ie. vizw.it/?gist=a304ce8fac9c14dfbf16). This allows viewers to fork the Gist and build their own VizWit page.

Configuration Documentation

Build your own

Visit the builder and add a few cards, then configure them using the wrench icon. When you're finished, click Export and copy the configuration code into a new "gist" at gist.github.com. Once you click Create, you should see your new "gist" and the "gist id" of random characters in the URL (ie. 813483da72ac781f8b13). Use that gist id to go to http://vizw.it?gist=YOUR_GIST_ID

Alternatively, use the live editor to edit the raw JSON alongside a live representation of it.

If you'd like to share what you've created, post an issue with a link to it.

Technology

VizWit is a client-side JavaScript application. The application is structured using Backbone. Charts are built using AmCharts. Maps are built using Leaflet. Tables are built using DataTables. Tests (of which there are not nearly enough!) are run using Mocha. The interactive layout is generated by Gridstack. The application is compiled using Browserify. See the full list of dependencies in package.json

How it works

vizwit.js is the primary chart-generating module. It takes a container selector and a config object and uses them to initialize a view (bar chart, map, table, etc.). The views are passed a collection and a filteredCollection, which are identical and allow the view to query the data provider. Views generate the chart/map/table/etc. and listen for user interactions on them. On an interaction, the view triggers the global event object with the filter (ie. state=PA), and all views that use the same dataset receive the event and use their filteredCollection to query the data provider with the filter passed through the event. By using a separate collection, VizWit can show the "filtered value" and the "original value" side-by-side.

The actual entry point is either vizwit-loader.js or vizwit-embed.js. vizwit-loader.js fetches a gist or local file, reads its configuration, and passes it to layout.js to create a layout on the page. Then for each chart in the configuration, layout.js calls init() from vizwit.js as described above. vizwit-embed.js simply finds the parent container of the <script> tag that was embedded, and calls init() from vizwit.js inside of it. This way of embedding allows the VizWit library to only be loaded once on the page with as many charts embedded in any element (example).

Development

  • After cloning the repo, use npm install to install dependencies
  • While developing, use npm start to automatically recompile when changes are made and run a web server at localhost:8080
  • Use npm test to verify code style and run unit tests
  • Use npm run build for a production build, and then use npm run deploy to push the dist/ directory to the gh-pages branch (first make the deploy script executable via chmod +x deploy.sh)

License

GPL-2 (create an issue if that doesn't work for someone)

vizwit's People

Contributors

gitter-badger avatar marks avatar talos avatar timwis avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vizwit's Issues

Decide whether to hide grid lines

Pretty sure this is a Tufte thing but not sure the result looks that nice.

Before:
screen shot 2015-09-07 at 13 13 38

After:
screen shot 2015-09-07 at 13 13 01

To enable, add settings:

  • chart.valueAxes[0].gridColor = '#fff'
  • chart.valueAxes[0].gridAlpha = 0.6
  • chart.gridAboveGraphs = true

Leaflet map renders before template is visible

Despite appending the template to the el before initializing Leaflet, it seems Leaflet's container is not visible upon initialization. As a temporary workaround, I'm using setTimeout() to cause a slight delay. Obviously this is not a permanent solution.

Add total record count to table

Table should know how many records there are total. It should probably also need to know how the total with the filters applied. I imagine the collection should handle this, but not sure best practice (should there be a model or two on the collection? Or just an AJAX request? When should they kick off? etc.)

docs

Map clicks throwing inconsequential error

Uncaught TypeError: Cannot read property 'mouseEventToContainerPoint' of null on most clicks. Doesn't appear to impact functionality, but didn't start happening until today.

Legend/baseline can change when showing filtered amounts

If an "original amount" bar chart has a legend from 100k to 1M and it gets filtered by another chart, and one of its bars has an amount of 5, it will change its legend to 0 to 1M to accommodate the new, smaller filtered amount, which changes how all of the original bars appear.

This is even more evident in the choropleth chart, which colorizes based on the min/max of either the original collection or the filtered collection.

The question is whether this is okay, or if it's too confusing.

Use field definitions in table

Columns should have human readable names tied to their field names. Panels should have descriptions. This could either be defined manually in a config file or fetched via a metadata API.

Cross-filtering should alter the viz data instead of re-rendering it

Probably more performant (especially w/map of census tracts); hopefully it's possible

idea:

init:
    collection.fetch()

on collection sync:
    render chart w/collection

on filtered:
    filterCollection.fetch()

on filterCollection sync:
    graph1 color = grey
    forEach graph1 column, find match in filterCollection, add value
    refresh chart

on click:
    highlight clicked column
    trigger filter

Default zoom on bar charts should be the left side

Right now the workaround is calling a zoom method after the chart loads. Ideally there'd be a default zoom in the config of the chart. The current method appears not to work consistently on mobile.

Allow cards to have base filters

For example, if the underlying dataset contains 5 years of data but the visualization should only show one year, we should be able to set a base filter on every card/chart/map/etc. that sticks.

Switch to amcharts

Looks like using "clustered": false inside the graphs objects puts the bars on top of each other.

screen shot 2015-08-30 at 18 52 06

Switch to config.json file

Currently configuring via HTML attributes. Switching to config.json configuration will require implementing templates.

Datetime chart has occasional error on chartCursor.addListener()

Occasionally I'll get an error about chartCursor.addListener not being a function on line 61

this.chart.chartCursor.addListener('selected', this.onClick);

Debugger suggests this.chart.chartCursor has not been initialized at the time of the error, and simply refers to the chartCursor definition passed to the AmCharts initialization method. The infrequency would suggest it's an async call not finishing quickly enough, but there don't appear to be any async calls that could be the culprit. Cannot reproduce so difficult to diagnose.

Improve chart horizontal scroll

Yes it works but it's a little confusing, slightly buggy, and doesn't seem to work on mobile

Perhaps use external buttons to navigate? example

Also, legend probably shouldn't reset as it's pretty confusing what's going on

Cleanup basechart

It may not even make sense to have a base chart. At the moment, it makes it harder to understand what's going on. It should probably be renamed "serial" since it's really only common for bar & datetime (not pie).

Map layer adding occasionally produces error

Cannot read property 'addLayer' of undefined on:

addTo: function (map) {
        map.addLayer(this);
        return this;
    },

This is probably occurring because the collection/boundaries finish syncing before the 100 ms timeout renders the map, so likely dependent on #24

Add choropleth map panel

Color of polygons should reflect the number of points residing within them. Not sure if we can use leaflet or turf.js for this or if we'll need to rely on server side processing with a high-volume dataset.

Idea: use collection.min() and .max() to get the floor & ceiling of the color options.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.