コード例 #1
0
 constructor(el, props = {}) {
   console.log(props)
   //we initiate charts in constructor
   this.gainOrLossChart = dc.pieChart('#gain-loss-chart');
   this.fluctuationChart = dc.barChart('#fluctuation-chart');
   this.quarterChart = dc.pieChart('#quarter-chart');
   this.dayOfWeekChart = dc.rowChart('#day-of-week-chart');
   this.moveChart = dc.lineChart('#monthly-move-chart');
   this.volumeChart = dc.barChart('#monthly-volume-chart');
   this.yearlyBubbleChart = dc.bubbleChart('#yearly-bubble-chart');
   this.nasdaqCount = dc.dataCount('.dc-data-count');
   this.nasdaqTable = dc.dataTable('.dc-data-table');
 }
コード例 #2
0
                d3.json('src/stores/untappd.json', function (error, data) {
                  var beerData = data.response.beers.items;

                  var fullDateFormat = d3.time.format('%a, %d %b %Y %X %Z');
                  var yearFormat = d3.time.format('%Y');
                  var monthFormat = d3.time.format('%b');
                  var dayOfWeekFormat = d3.time.format('%a');

                  // normalize/parse data so dc can correctly sort & bin them
                  // I like to think of each "d" as a row in a spreadsheet
                  beerData.forEach(d => {
                    d.count = +d.count;
                    // round to nearest 0.25
                    d.rating_score = Math.round(+d.rating_score * 4) / 4;
                    d.beer.rating_score = Math.round(+d.beer.rating_score *4) / 4;
                    // round to nearest 0.5
                    d.beer.beer_abv = Math.round(+d.beer.beer_abv * 2) / 2;
                    // round to nearest 10
                    d.beer.beer_ibu = Math.floor(+d.beer.beer_ibu / 10) * 10;

                    d.first_had_dt = fullDateFormat.parse(d.first_had);
                    d.first_had_year = +yearFormat(d.first_had_dt);
                    d.first_had_month = monthFormat(d.first_had_dt);
                    d.first_had_day = dayOfWeekFormat(d.first_had_dt);
                  });

                  // set crossfilter
                  var ndx = crossfilter(beerData);

                  // create dimensions (x-axis values)
                  var yearDim  = ndx.dimension(function(d) {return d.first_had_year;}),
                      // pluck: short-hand for same kind of anon. function we used for yearDim
                      monthDim  = ndx.dimension(pluck('first_had_month')),
                      dayOfWeekDim = ndx.dimension(pluck('first_had_day')),
                      ratingDim = ndx.dimension(pluck('rating_score')),
                      commRatingDim = ndx.dimension(function(d) {return d.beer.rating_score;}),
                      abvDim = ndx.dimension(function(d) {return d.beer.beer_abv;}),
                      ibuDim = ndx.dimension(function(d) {return d.beer.beer_ibu;}),
                      allDim = ndx.dimension(function(d) {return d;});

                  // create groups (y-axis values)
                  var all = ndx.groupAll();
                  var countPerYear = yearDim.group().reduceCount(),
                      countPerMonth = monthDim.group().reduceCount(),
                      countPerDay = dayOfWeekDim.group().reduceCount(),
                      countPerRating = ratingDim.group().reduceCount(),
                      countPerCommRating = commRatingDim.group().reduceCount(),
                      countPerABV = abvDim.group().reduceCount(),
                      countPerIBU = ibuDim.group().reduceCount();

                  // specify charts
                  var yearChart   = pieChart('#chart-ring-year'),
                      monthChart   = pieChart('#chart-ring-month'),
                      dayChart   = pieChart('#chart-ring-day'),
                      ratingCountChart  = barChart('#chart-rating-count'),
                      commRatingCountChart  = barChart('#chart-community-rating-count'),
                      abvCountChart  = barChart('#chart-abv-count'),
                      ibuCountChart  = barChart('#chart-ibu-count');
                    var  myDataCount = dataCount('#data-count');
                    var  myDataTable = dataTable('#data-table');

                  yearChart
                      .width(150)
                      .height(150)
                      .dimension(yearDim)
                      .group(countPerYear)
                      .innerRadius(20);

                  monthChart
                      .width(150)
                      .height(150)
                      .dimension(monthDim)
                      .group(countPerMonth)
                      .innerRadius(20)
                      .ordering(function (d) {
                        var order = {
                          'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4,
                          'May': 5, 'Jun': 6, 'Jul': 7, 'Aug': 8,
                          'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12
                        };
                        return order[d.key];
                      });

                  dayChart
                      .width(150)
                      .height(150)
                      .dimension(dayOfWeekDim)
                      .group(countPerDay)
                      .innerRadius(20)
                      .ordering(function (d) {
                        var order = {
                          'Mon': 0, 'Tue': 1, 'Wed': 2, 'Thu': 3,
                          'Fri': 4, 'Sat': 5, 'Sun': 6
                        }
                        return order[d.key];
                      }
                     );

                  ratingCountChart
                      .width(300)
                      .height(180)
                      .dimension(ratingDim)
                      .group(countPerRating)
                      .x(d3.scale.linear().domain([0,5.2]))
                      .elasticY(true)
                      .centerBar(true)
                      .barPadding(5)
                      .xAxisLabel('My rating')
                      .yAxisLabel('Count')
                      .margins({top: 10, right: 20, bottom: 50, left: 50});
                  ratingCountChart.xAxis().tickValues([0, 1, 2, 3, 4, 5]);

                  commRatingCountChart
                      .width(300)
                      .height(180)
                      .dimension(commRatingDim)
                      .group(countPerCommRating)
                      .x(d3.scale.linear().domain([0,5.2]))
                      .elasticY(true)
                      .centerBar(true)
                      .barPadding(5)
                      .xAxisLabel('Community rating')
                      .yAxisLabel('Count')
                      .margins({top: 10, right: 20, bottom: 50, left: 50});
                  commRatingCountChart.xAxis().tickValues([0, 1, 2, 3, 4, 5]);

                  abvCountChart
                      .width(300)
                      .height(180)
                      .dimension(abvDim)
                      .group(countPerABV)
                      .x(d3.scale.linear().domain([-0.2, d3.max(beerData, function (d) { return d.beer.beer_abv; }) + 0.2]))
                      .elasticY(true)
                      .centerBar(true)
                      .barPadding(2)
                      .xAxisLabel('Alcohol By Volume (%)')
                      .yAxisLabel('Count')
                      .margins({top: 10, right: 20, bottom: 50, left: 50});

                  ibuCountChart
                      .width(300)
                      .height(180)
                      .dimension(ibuDim)
                      .group(countPerIBU)
                      .x(d3.scale.linear().domain([-2, d3.max(beerData, function (d) { return d.beer.beer_ibu; }) + 2]))
                      .elasticY(true)
                      .centerBar(true)
                      .barPadding(5)
                      .xAxisLabel('International Bitterness Units')
                      .yAxisLabel('Count')
                      .xUnits(function (d) { return 5;})
                      .margins({top: 10, right: 20, bottom: 50, left: 50});

                  myDataCount
                      .dimension(ndx)
                      .group(all);

                   myDataTable
                    .dimension(allDim)
                    .group(function (d) { return 'dc.js insists on putting a row here so I remove it using JS'; })
                    .size(100)
                    .columns([
                      function (d) { return d.brewery.brewery_name; },
                      function (d) { return d.beer.beer_name; },
                      function (d) { return d.beer.beer_style; },
                      function (d) { return d.rating_score; },
                      function (d) { return d.beer.rating_score; },
                      function (d) { return d.beer.beer_abv; },
                      function (d) { return d.beer.beer_ibu; }
                    ])
                    .sortBy(pluck('rating_score'))
                    .order(d3.descending)
                    .on('renderlet', function (table) {
                      // each time table is rendered remove nasty extra row dc.js insists on adding
                      table.select('tr.dc-table-group').remove();
                    });

                  // register handlers
                  d3.selectAll('a#all').on('click', function () {
                    filterAll();
                    renderAll();
                  });

                  d3.selectAll('a#year').on('click', function () {
                    yearChart.filterAll();
                    redrawAll();
                  });

                  d3.selectAll('a#month').on('click', function () {
                    monthChart.filterAll();
                    redrawAll();
                  });

                  d3.selectAll('a#day').on('click', function () {
                    dayChart.filterAll();
                    redrawAll();
                  });

                  // showtime!
                  renderAll();

                });
コード例 #3
0
 renderDC = (selectedTimespan) => {
   const { formatMessage } = this.props.intl;
   // show a spinner while it loads
   this.showLoading(true);
   // set up chart containers
   const storiesOverTimeChart = dc.barChart('#stories-over-time-chart');
   const storyCount = dc.dataCount('#story-counts');
   const languageChart = dc.pieChart('#language-chart');
   const TopicStoryTable = dc.dataTable('#story-table');
   const facebookShareChart = dc.barChart('#facebook-share-chart');
   const inlinkChart = dc.barChart('#inlink-chart');
   // load the data up
   d3.csv(this.csvFileUrl(), (data) => {
     this.showLoading(false);
     // set up some binning
     const maxFacebookShares = d3.max(data.map(d => d.facebook_share_count));
     const facebookBinSize = maxFacebookShares / FACEBOOK_BIN_COUNT;
     const maxInlinks = d3.max(data.map(d => d.media_inlink_count));
     const inlinkBinSize = d3.max([1, (maxInlinks / INLINK_BIN_COUNT)]); // don't do < 1 for bin size
     // clean up the data
     for (let i = 0; i < data.length; i += 1) {
       const d = data[i];
       d.publishDate = (d.publish_date === STORY_PUB_DATE_UNDATEABLE) ? null : storyPubDateToMoment(d.publish_date).toDate();
       d.publishMonth = (d.publish_date === STORY_PUB_DATE_UNDATEABLE) ? null : d.publishDate.getMonth(); // pre-calculate month for better performance
       d.facebook_share_count = +d.facebook_share_count;
       d.inlink_count = +d.inlink_count;
       d.media_id = +d.media_id;
       d.media_inlink_count = +d.media_inlink_count;
       d.outlink_count = +d.outlink_count;
       d.domain = storyDomainName(d);
     }
     // set up all the dimensions and groups that feed the charts
     const dateExtents = [selectedTimespan.startDateObj, selectedTimespan.endDateObj];
     const totalDays = moment(selectedTimespan.endDateObj).diff(moment(selectedTimespan.startDateObj), 'days');
     const ndx = crossfilter(data);
     const all = ndx.groupAll();
     const publishDateDimension = ndx.dimension(d => d.publishDate);
     const publishDateGroup = publishDateDimension.group(); // .reduceSum(() => 1);
     const languageDimension = ndx.dimension(d => d.language);
     const languageGroup = languageDimension.group();
     const facebookDimension = ndx.dimension(d => d.facebook_share_count);
     const facebookGroup = facebookDimension.group(d => Math.floor(d / facebookBinSize) * facebookBinSize);
     const inlinkDimension = ndx.dimension(d => d.media_inlink_count);
     const inlinkGroup = inlinkDimension.group(d => Math.floor(d / inlinkBinSize) * inlinkBinSize);
     // histogram of stories
     storiesOverTimeChart
       .width(1000).height(200)
       .dimension(publishDateDimension)
       .group(publishDateGroup)
       .elasticY(true)
       .gap(0)
       .x(d3.scaleTime().domain(dateExtents))
       .xUnits(() => totalDays)
       .yAxisLabel(formatMessage(localMessages.storiesChartY))
       .xAxisLabel(formatMessage(localMessages.storiesChartX));
     // language pie chart
     languageChart
       .width(180).height(180)
       .radius(80)
       .turnOnControls(true)
       .controlsUseVisibility(false)
       .dimension(languageDimension)
       .group(languageGroup);
     // facebook share histogram
     facebookShareChart
       .width(380).height(200)
       .group(facebookGroup)
       .dimension(facebookDimension)
       .gap(1)
       .x(d3.scaleLinear().domain([0, maxFacebookShares]))
       .xUnits(() => FACEBOOK_BIN_COUNT)
       .xAxisLabel(formatMessage(localMessages.facebookChartX))
       .yAxisLabel(formatMessage(localMessages.facebookChartY))
       .renderHorizontalGridLines(true);
     // media inlink histogram
     inlinkChart
       .width(380).height(200)
       .group(inlinkGroup)
       .dimension(inlinkDimension)
       .gap(1)
       .x(d3.scaleLinear().domain([0, maxInlinks]))
       .xUnits(() => d3.min([maxInlinks, INLINK_BIN_COUNT]))
       .yAxisLabel(formatMessage(localMessages.inlinkChartY))
       .xAxisLabel(formatMessage(localMessages.inlinkChartX))
       .renderHorizontalGridLines(true);
     // show how many stories are included
     storyCount
       .dimension(ndx)
       .group(all);
     // and set up the story table
     TopicStoryTable
       .dimension(publishDateDimension)
       .size(50)
       .group((d) => {
         let monthStr = null;
         if (d.publishDate !== null) { // ignore undateable ones
           const format = d3.format('02d');
           monthStr = `${d.publishDate.getFullYear()}/${format((d.publishDate.getMonth() + 1))}`;
         }
         return monthStr;
       })
       .showGroups(false)
       .columns([
         d => ((d.publishDate === null) ? STORY_PUB_DATE_UNDATEABLE : moment(d.publishDate).format('MMM D, YYYY')),
         d => `<img className="google-icon" src=${googleFavIconUrl(d.domain)} alt=${d.domain} />`,
         d => d.media_name,
         d => `<a href=${d.url} target="_blank">${d.title}</a>`,
         d => d.media_inlink_count,
         d => d.outlink_count,
         d => d.facebook_share_count,
       ])
       .sortBy(d => d.media_inlink_count) // TODO: make this selectable
       .order(d3.descending);
     this.setState({
       charts: {
         languageChart,
         facebookShareChart,
         inlinkChart,
         storiesOverTimeChart,
       },
     });
     dc.renderAll();
   });
 }
コード例 #4
0
ファイル: transaction-chart.js プロジェクト: agdsn/pycroft
$(function () {
    var dateFormat = d3.time.format('%Y-%m-%d');

    //todo custom reduce functions for server-side stuff
    var volumeChart = dc.barChart('#volume-chart');
    var valueChart = dc.compositeChart('#value-chart');
    var amountChart = dc.barChart(valueChart);
    var cumAmountChart = dc.lineChart(valueChart);
    var accountChart = dc.rowChart('#account-selector');
    var typeChart = dc.rowChart('#account-type-selector');
    var transactionTable = dc.dataTable('#transaction-table');
    var transactionCount = dc.dataCount(".dc-data-count");
    var params = (new URL(document.location)).searchParams;
    var dateMin = dateFormat.parse(params.get('after'));
    var dateMax = dateFormat.parse(params.get('before'));

    $("#reset-all").click(function () {
        dc.filterAll();
        dc.renderAll();
        return false;
    });
    $("#reset-volume-chart").click(function () {
        volumeChart.filterAll();
        dc.redrawAll();
        return false;
    });

    var url = new URL($SCRIPT_ROOT + '/transactions/json');
    url.search = document.location.search;
    d3.json(url.toString(), function (resp) {

        data = resp.items;
        data.forEach(function (d) {
            d.dd = dateFormat.parse(d.valid_on);
            d.month = d3.time.month(d.dd);
        });

        var ndx = crossfilter(data);
        var all = ndx.groupAll();

        var transaction = ndx.dimension(function (d) {
            return d.account_id;
        });
        var transactionGroup = transaction.groupAll();
        transactionCount
            .dimension(ndx)
            .group(transactionGroup);

        var account = ndx.dimension(function (d) {
            return d.account_id;
        });
        var accountGroup = account.group();
        var accountCache = {"Others": "Other accounts"}; //dict of values cached
        var accountReq = new Set([]); //set of ids being requested

        // todo url_for
        var accountName = function (acc_id, format_func, action_func) {
            if (!(acc_id in accountCache)) {
                var href = "/finance/accounts/" + acc_id;
                if (!accountReq.has(acc_id)) {
                    accountReq.add(acc_id);
                    jQuery.getJSON(href + "/json?limit=0", function (data) {
                        accountCache[acc_id] = data.name;
                        action_func(acc_id, data.name);
                    }).complete(function () {
                        accountReq.delete(acc_id);
                    });
                }
                return format_func(acc_id);
            } else {
                return accountCache[acc_id];
            }
        };

        accountChart
            .height(300)
            .width(250)
            .dimension(account)
            .group(accountGroup)
            .cap(10)
            .x(d3.scale.linear().range([1, 100]))
            .label(function (d) {
                var format_func = function (acc_id) {
                    return "acc-" + acc_id;
                };
                var action_func = function (acc_id, replacement) {
                    jQuery('text:contains("' + format_func(acc_id) + '")').text(replacement);
                };
                return accountName(d.key, format_func, action_func);
            })
            .ordering(function (d) {
                return -d.value;
            })
            .renderLabel(true)
            .xAxis().tickValues([]);

        var accountType = ndx.dimension(function (d) {
            return d.type;
        });
        var accountTypeGroup = accountType.group();

        typeChart
            .height(300)
            .width(250)
            .dimension(accountType)
            .group(accountTypeGroup)
            .cap(10)
            .x(d3.scale.linear().range([1, 100]))
            .label(function (d) {
                return d.key + " (" + d.value + ")";
            })
            .renderLabel(true)
            .xAxis().tickValues([]);

        var dateDimension = ndx.dimension(function (d) {
            return d.dd;
        });
        var monthDimension = ndx.dimension(function (d) {
            return d.month;
        });

        var dateAccessor = function (d) {
            return d.dd;
        };
        dateExtent = [];
        dateExtent = d3.extent(data, dateAccessor);
        if (!(dateMin === null)) {
            dateExtent[0] = dateMin;
        }
        if (!(dateMax === null)) {
            dateExtent[1] = dateMax;
        }


        var monthGroup = monthDimension.group().reduceCount();
        volumeChart
            .width(700)
            .height(100)
            .dimension(monthDimension)
            .group(monthGroup)
            .x(d3.time.scale().domain(dateExtent))
            .gap(0) // gap(0) has overlaps for some reason
            .xUnits(d3.time.months) //seems to be buggy, so we can't set bar width :(
            // logscale would also be nice, but that too is buggy
            .elasticY(true)
            .margins({top: 0, left: 70, right: 70, bottom: 25})
            .renderHorizontalGridLines(true)
            .renderVerticalGridLines(true)
            .yAxisLabel("# transactions");

        var valueGroup = monthDimension.group().reduceSum(function (d) {
            return d.amount;
        });
        var cumValueGroup = {
            all: function () {
                var s = 0;
                var g = [];
                valueGroup.all().forEach(function (d, i) {
                    s += d.value;
                    g.push({key: d.key, value: s});
                });
                return g;
            },
        };

        amountChart
            .dimension(monthDimension)
            .group(valueGroup, "Monthly amount transacted");

        cumAmountChart
            .dimension(monthDimension)
            .group(cumValueGroup, "Cumulative amount transacted")
            .ordinalColors(["orange"])
            .useRightYAxis(true)
            .interpolate("step-after");

        valueChart
            .width(700)
            .height(200)
            .dimension(monthDimension)
            .x(d3.time.scale().domain(dateExtent))
            .xUnits(d3.time.months)
            .elasticY(true)
            .brushOn(false)
            .margins({top: 0, left: 70, right: 70, bottom: 25})
            .renderHorizontalGridLines(true)
            .renderVerticalGridLines(true)
            .yAxisLabel("monthly net amount transacted")
            .rightYAxisLabel("total net amount transacted")
            .rangeChart(volumeChart)
            .legend(dc.legend().x(90).y(0).itemHeight(13).gap(5))
            .compose([amountChart, cumAmountChart]);


        var linkTemplate = _.template(
            '<a id="<%= id %>" href="<%= href %>"><%= title %></a>',
        );

        var descCache = {};
        var descReq = new Set([]);

        transactionTable
            .dimension(dateDimension)
            .columns([
                function (d) {
                    return d.amount / 100. + "&#x202F;€";
                },
                function (d) {
                    var format_func = function (acc_id) {
                        return "<span id=\"acc-" + acc_id + "\"></span>";
                    };
                    var action_func = function (acc_id, replacement) {
                        jQuery('#acc-' + acc_id).text(replacement);
                    };
                    return accountName(d.account_id, format_func, action_func);
                },
                function (d) {
                    return d.type;
                },
            ])

            .group(function (d) {
                var href = "/finance/transactions/" + d.id;
                // if building template is too slow, jquery may be executed
                // before document is generated :(
                var desc = "Link";
                if (!(d.id in descCache)) {
                    if (!descReq.has(d.id)) {
                        descReq.add(d.id);
                        jQuery.getJSON(href + "/json", function (data) {
                            jQuery('a[href="' + href + '"]').text(data.description);
                            descCache[d.id] = data.description;
                            descReq.delete(d.id);
                        });
                    }
                } else {
                    desc = descCache[d.id];
                }
                var date = d3.time.format("%Y-%m-%d")(d.dd);
                var link = linkTemplate({
                    'id': "transaction-link",
                    'href': href,
                    'title': desc,
                });
                return date + " " + link;
            })
            .sortBy(function (d) {
                return -d.id;
            })
            .size(15);

        //TODO transaction value chart (count vs value)
        //TODO total value transacted chart (count vs value)

        dc.renderAll();
    });
});