chartit package¶
Subpackages¶
Submodules¶
chartit.chartdata module¶
-
class
chartit.chartdata.DataPool(series)¶ Bases:
objectDataPool holds the data retrieved from various models (tables).
-
__dict__= mappingproxy({'__dict__': <attribute '__dict__' of 'DataPool' objects>, '_get_data': <function DataPool._get_data>, '__init__': <function DataPool.__init__>, '_group_terms_by_query': <function DataPool._group_terms_by_query>, '__doc__': 'DataPool holds the data retrieved from various models (tables).', '__module__': 'chartit.chartdata', '_generate_vqs': <function DataPool._generate_vqs>, '__weakref__': <attribute '__weakref__' of 'DataPool' objects>})¶
-
__init__(series)¶ Create a DataPool object as specified by the
series.Arguments: series (list of dict) - specifies the what data to retrieve and where to retrieve it from. It is of the form
[{'options': { 'source': a django model, Manager or QuerySet, }, 'terms': [ 'a_valid_field_name', ... , {'any_name': 'a_valid_field_name', ... }, ] }, ... ]
Where
- options (required) - a
dict. Any of the series options for the Highchartsoptionsobject are valid. - terms - is a list. Each element in
termsis either- a
str- needs to be a valid model field for the correspondingsource, or - a
dict- need to be of the form{'any_name': 'a_valid_field_name', ...}.
- a
To retrieve data from multiple models or QuerySets, just add more dictionaries with the corresponding
optionsand terms.- options (required) - a
Raises: - APIInputError - sif the
seriesargument has any invalid parameters.
Warning
All elements in
termsmust be unique across all the dictionaries in theserieslist. If there are two terms with samename, the latter one is going to overwrite the one before it.For example, the following is wrong:
[{'options': { 'source': SomeModel}, 'terms':[ 'foo', 'bar']}, {'options': { 'source': OtherModel}, 'terms':[ 'foo']}]
In this case, the term
foofromOtherModelis going to overwritefoofromSomeModel.Here is the right way of retrieving data from two different models both of which have the same field name.
[{'options': { 'source': SomeModel}, 'terms':[ 'foo', 'bar']}, {'options': { 'source': OtherModel}, 'terms':[ {'foo_2': 'foo'}]}]
-
__module__= 'chartit.chartdata'¶
-
__weakref__¶ list of weak references to the object (if defined)
-
_generate_vqs()¶
-
_get_data()¶
-
_group_terms_by_query(sort_by_term=None, *addl_grp_terms)¶ Groups all the terms that can be extracted in a single query. This reduces the number of database calls.
Returns: - a list of sub-lists where each sub-list has items that can all be retrieved with the same query (i.e. terms from the same source and any additional criteria as specified in addl_grp_terms).
-
-
class
chartit.chartdata.PivotDataPool(series, top_n_term=None, top_n=None, pareto_term=None, sortf_mapf_mts=None)¶ Bases:
chartit.chartdata.DataPoolPivotDataPool holds the data retrieved from various tables (models) and then pivoted against the category fields.
-
__init__(series, top_n_term=None, top_n=None, pareto_term=None, sortf_mapf_mts=None)¶ Creates a PivotDataPool object.
Arguments: series (required) - a list of dicts that specifies the what data to retrieve, where to retrieve it from and how to pivot the data. It is of the form
[{'options': { 'source': django Model, Manager or QuerySet , 'categories': ['a_valid_field', ...], 'legend_by': ['a_valid_field', ...] (optional), 'top_n_per_cat': a number (optional), }, 'terms': { 'any_name_here': django Aggregate, 'some_other_name':{ 'func': django Aggregate, #any options to override ... }, ... } }, ... #repeat dicts with 'options' & 'terms' ]
Where
options - is a dict that specifies the common options for all the terms.
source (required) - is either a
Model,Manageror aQuerySet.categories (required) - is a list of model fields by which the data needs to be pivoted by. If there is only a single item,
categoriescan just be a string instead of a list with single element.For example if you have a model with
country,state,county,city,date,rainfall,temperatureand you want to pivot the data bycountryandstate, thencategories = ['country', 'state'].Note
Order of elements in the
categorieslist matters!categories = ['country', 'state']groups your data first bycountryand then bystatewhen running the SQL query. This obviously is not the same as grouping bystatefirst and then bycountry.legend_by (optional) - is a list of model fields by which the data needs to be legended by. For example, in the above case, if you want to legend by
countyandcity, thenlegend_by = ['county', 'city']Note
Order of elements in the
legend_bylist matters!See the note in
categoriesabove.top_n_per_cat (optional) - The number of top items that the legended entries need to be limited to in each category. For example, in the above case, if you wanted only the top 3
county/citieswith highest rainfall for each of thecountry/state, thentop_n_per_cat = 3.
terms - is a
dict. The keys can be any strings (but helps if they are meaningful aliases for the field). The values can either be- a django
Aggregate: of a valid field in corresponding model. For example,Avg('temperature'),Sum('price'), etc. or - a
dict: In this case thefuncmust specify relevant django aggregate to retrieve. For example'func': Avg('price'). The dict can also have any additional entries from the options dict. Any entries here will override the entries in theoptionsdict.
- a django
top_n_term (optional) - a string. Must be one of the keys in the corresponding
termsin theseriesargument.top_n (optional) - an integer. The number of items for the corresponding
top_n_termthat need to be retained.If
top_n_termandtop_nare present, only thetop_nnumberof items are going to displayed in the pivot chart. For example, if you want to plot only the top 5 states with highest average rainfall, you can do something like this.PivotDataPool( series = [ {'options': { 'source': RainfallData.objects.all(), 'categories': 'state'}, 'terms': { 'avg_rain': Avg('rainfall')}}], top_n_term = 'avg_rain', top_n = 5)
Note that the
top_n_termis'avg_rain'and notstate; because we want to limit by the average rainfall.pareto_term (optional) - the term with respect to which the pivot chart needs to be paretoed by.
For example, if you want to plot the average rainfall on the y-axis w.r.t the state on the x-axis and want to pareto by the average rainfall, you can do something like this.
PivotDataPool( series = [ {'options': { 'source': RainfallData.objects.all(), 'categories': 'state'}, 'terms': { 'avg_rain': Avg('rainfall')}}], pareto_term = 'avg_rain')
sortf_mapf_mts (optional) - a
tuplewith three elements of the form(sortf, mapf, mts)wheresortf - is a function (or a callable) that is used as a key when sorting the category values.
For example, if
categories = 'month_num'and if the months need to be sorted in reverse order, thensortfcan besortf = lambda *x: (-1*x[0],)
Note
sortfis passed the category values as tuples and must return tuples!If
categoriesis['city', 'state']and if the category values returned need to be sorted with state first and then city, thensortfcan besortf = lambda *x: (x[1], x[0])
The above
sortfis passed tuples like('San Francisco', 'CA'),('New York', 'NY'),...and it returns tuples like('CA', 'San Francisco'),('NY', 'New York'),...which when used as keys to sort the category values will obviously first sort by state and then by city.mapf - is a function (or a callable) that defines how the category values need to be mapped.
For example, let’s say
categoriesis'month_num'and that the category values that are retrieved from your database are1,2,3, etc. If you want month names as the category values instead of month numbers, you can define amapfto transform the month numbers to month names like sodef month_name(*t): names ={1: 'Jan', 2: 'Feb', 3: 'Mar', 4: 'Apr', 5: 'May', 6: 'Jun', 7: 'Jul', 8: 'Aug', 9: 'Sep', 10: 'Oct', 11: 'Nov', 12: 'Dec'} month_num = t[0] return (names[month_num], ) mapf = month_name
Note
mapflikesortfis passed the category values as tuples and must return tuples.mts - map then sort ; a
bool. IfTrue, the category values are mapped first and then sorted, and ifFalsecategory values are sorted first and then mapped.In the above example of month names, we
mtsmust beFalsebecause the months must first be sorted based on their number and then mapped to their names. IfmtsisTrue, the month numbers would be transformed to the month names, and then sorted, which would yield an order likeApr,Aug,Dec, etc. (not what we want).
Raises: - APIInputError - if the
seriesargument has any invalid parameters.
Here is a full example of a
seriesterm that retrieves the average temperature of the top 3 cities in each country/state and the average rainfall of the top 2 cities in each country/state.[{'options': { 'source': Weather.objects.all(), 'categories': ['country', 'state'], 'legend_by': 'city', 'top_n_per_cat': 3}, 'terms': { 'avg_temp': Avg('temperature'), 'avg_rain': { 'func': Avg('rainfall'), 'top_n_per_cat': 2}}}]
The
'top_n_per_cat': 2term inavg_raindict overrides'top_n_per_cat': 5from the comon options dict. Effectively, the aboveseriesretrieves the top 2citieswith highestavg_rainin eachcountry/stateand top 3citieswith highestavg_tempin eachcountry/state.A single
PivotDataPoolcan hold data from multiple Models. If there are more models or QuerySets to retrieve the data from, just add more dicts to the series list with differentsourcevalues.Warning
The
keysfor thetermsmust be unique across all the dictionaries in theserieslist! If there are multiple terms with samekey, the latter ones will just overwrite the previous ones.For instance, the following example is wrong.
[{'options': { 'source': EuropeWeather.objects.all(), 'categories': ['country', 'state']}, 'terms': { 'avg_temp': Avg('temperature')}}, {'options': { 'source': AsiaWeather.objects.all(), 'categories': ['country', 'state']}, 'terms': { 'avg_temp': Avg('temperature')}}]
The second
avg_tempwill overwrite the first one. Instead just use different names for each of the keys in all the dictionaries. Here is the right format.[{'options': { 'source': EuropeWeather.objects.all(), 'categories': ['country', 'state']}, 'terms': { 'europe_avg_temp': Avg('temperature')}}, {'options': { 'source': AsiaWeather.objects.all(), 'categories': ['country', 'state']}, 'terms': { 'asia_avg_temp': Avg('temperature')}}]
-
__module__= 'chartit.chartdata'¶
-
_generate_vqs()¶ Generates and yields the value query set for each query in the query group.
-
_get_data()¶
-
chartit.charts module¶
-
class
chartit.charts.BaseChart¶ Bases:
objectCommon ancestor class for all charts to avoid code duplication.
-
__dict__= mappingproxy({'__dict__': <attribute '__dict__' of 'BaseChart' objects>, '__init__': <function BaseChart.__init__>, 'to_json': <function BaseChart.to_json>, '__module__': 'chartit.charts', '__doc__': '\n Common ancestor class for all charts to avoid code duplication.\n ', '__weakref__': <attribute '__weakref__' of 'BaseChart' objects>})¶
-
__init__()¶
-
__module__= 'chartit.charts'¶
-
__weakref__¶ list of weak references to the object (if defined)
-
to_json()¶ Load Chart’s data as JSON Useful in Ajax requests. Example:
Return JSON from this method and response to client:
return JsonResponse(cht.to_json(), safe=False)
Then use jQuery load data and create Highchart:
$(function(){ $.getJSON("/data",function(data){ $('#container').highcharts(JSON.parse(data)); }); });
-
-
class
chartit.charts.Chart(datasource, series_options, chart_options=None, x_sortf_mapf_mts=None)¶ Bases:
chartit.charts.BaseChart-
__init__(datasource, series_options, chart_options=None, x_sortf_mapf_mts=None)¶ Chart accept the datasource and some options to create the chart and creates it.
Arguments:
datasource (required) - a
DataPoolobject that holds the terms and other information to plot the chart from.series_options (required) - specifies the options to plot the terms on the chart. It is of the form
[{'options': { #any items from HighChart series. For ex., 'type': 'column' }, 'terms': { 'x_name': ['y_name', {'other_y_name': { #overriding options}}, ...], ... }, }, ... #repeat dicts with 'options' & 'terms' ]
Where -
options (required) - a
dict. Any of the parameters from the Highcharts options object - series array are valid as entries in theoptionsdict exceptdata(because data array is generated from your datasource by chartit). For example,type,xAxis, etc. are all valid entries here.Note
The items supplied in the options dict are not validated to make sure that Highcharts actually supports them. Any invalid options are just passed to Highcharts JS which silently ignores them.
terms (required) - a
dict. keys are the x-axis terms and the values are lists of y-axis terms for that particular x-axis term. Both x-axis and y-axis terms must be present in the corresponding datasource, otherwise an APIInputError is raised.The entries in the y-axis terms list must either be a
stror adict. If entries are dicts, the keys need to be valid y-term names and the values need to be any options to override the default options. For example,[{'options': { 'type': 'column', 'yAxis': 0}, 'terms': { 'city': [ 'temperature', {'rainfall': { 'type': 'line', 'yAxis': 1}}]}}]
plots a column chart of city vs. temperature as a line chart on yAxis: 0 and city vs. rainfall as a line chart on yAxis: 1. This can alternatively be expressed as two separate entries:
[{'options': { 'type': 'column', 'yAxis': 0}, 'terms': { 'city': [ 'temperature']}}, {'options': { 'type': 'line', 'yAxis': 1}, 'terms': { 'city': [ 'rainfall']}}]
chart_options (optional) - a
dict. Any of the options from the Highcharts options object are valid (except the options in theseriesarray which are passed in theseries_optionsargument. The followingchart_optionsfor example, set the chart title and the axes titles.{'chart': { 'title': { 'text': 'Weather Chart'}}, 'xAxis': { 'title': 'month'}, 'yAxis': { 'title': 'temperature'}}
Note
The items supplied in the
chart_optionsdict are not validated to make sure that Highcharts actually supports them. Any invalid options are just passed to Highcharts JS which silently ignores them.
Raises:
APIInputErrorif any of the terms are not present in the corresponding datasource or if theseries_optionscannot be parsed.
-
__module__= 'chartit.charts'¶
-
_groupby_x_axis_and_vqs()¶ Here is an example of what this function would return
{ 0: { 0: {'month_seattle': ['seattle_temp']}, 1: {'month': ['houston_temp', 'boston_temp']} } }
In the above example,
- the inner most dict keys (‘month’ and ‘month_seattle’) are on the same xAxis (xAxis 0), just groupped in 2 groups (0 and 1)
- the inner most list values are from same ValueQuerySet (table)
If you decide to display multiple chart types with multiple axes then the return value will look like this
{ 0: { 0: {'month': ['boston_temp']} }, 1: { 0: {'month': ['houston_temp']} } }
- the outer most 0 and 1 are the numbers of the x axes
- the inner most 0 shows that each axis has 1 data group
-
_set_default_hcoptions(chart_options)¶ Set some default options, like xAxis title, yAxis title, chart title, etc.
-
generate_plot()¶
-
-
class
chartit.charts.PivotChart(datasource, series_options, chart_options=None)¶ Bases:
chartit.charts.BaseChart-
__init__(datasource, series_options, chart_options=None)¶ Creates the PivotChart object.
Arguments:
datasource (required) - a
PivotDataPoolobject that holds the terms and other information to plot the chart from.series_options (required) - specifies the options to plot the terms on the chart. It is of the form
[{'options': { #any items from HighChart series. For ex. 'type': 'column' }, 'terms': [ 'a_valid_term', 'other_valid_term': { #any options to override. For ex. 'type': 'area', ... }, ... ] }, ... #repeat dicts with 'options' & 'terms' ]
Where -
options (required) - a
dict. Any of the parameters from the Highcharts options object - series array are valid as entries in theoptionsdict exceptdata(because data array is generated from your datasource by chartit). For example,type,xAxis, etc. are all valid entries here.Note
The items supplied in the options dict are not validated to make sure that Highcharts actually supports them. Any invalid options are just passed to Highcharts JS which silently ignores them.
terms (required) - a
list. Only terms that are present in the corresponding datasource are valid.Note
All the
termsare plotted on they-axis. The categories of the datasource are plotted on the x-axis. There is no option to override this.Each of the
termsmust either be astror adict. If entries are dicts, the keys need to be valid terms and the values need to be any options to override the default options. For example,[{'options': { 'type': 'column', 'yAxis': 0}, 'terms': [ 'temperature', {'rainfall': { 'type': 'line', 'yAxis': 1}}]}]
plots a pivot column chart of temperature on yAxis: 0 and a line pivot chart of rainfall on yAxis: 1. This can alternatively be expressed as two separate entries:
[{'options': { 'type': 'column', 'yAxis': 0}, 'terms': [ 'temperature']}, {'options': { 'type': 'line', 'yAxis': 1}, 'terms': [ 'rainfall']}]
chart_options (optional) - a
dict. Any of the options from the Highcharts options object are valid (except the options in theseriesarray which are passed in theseries_optionsargument. The followingchart_optionsfor example, set the chart title and the axes titles.{'chart': { 'title': { 'text': 'Weather Chart'}}, 'xAxis': { 'title': 'month'}, 'yAxis': { 'title': 'temperature'}}
Note
The items supplied in the
chart_optionsdict are not validated to make sure that Highcharts actually supports them. Any invalid options are just passed to Highcharts JS which silently ignores them.
Raises:
APIInputErrorif any of the terms are not present in the corresponding datasource or if theseries_optionscannot be parsed.
-
__module__= 'chartit.charts'¶
-
generate_plot()¶
-
set_default_hcoptions()¶
-
chartit.exceptions module¶
Global ChartIt exception and warning classes.
chartit.utils module¶
utility and helper functions.
-
class
chartit.utils.RecursiveDefaultDict(data=None)¶ Bases:
dictBehaves exactly the same as a collections.defaultdict but works with pickle.loads. Fixes #10.
-
__dict__= mappingproxy({'__setitem__': <function RecursiveDefaultDict.__setitem__>, '__dict__': <attribute '__dict__' of 'RecursiveDefaultDict' objects>, '__init__': <function RecursiveDefaultDict.__init__>, '__getitem__': <function RecursiveDefaultDict.__getitem__>, 'update': <function RecursiveDefaultDict.update>, '__module__': 'chartit.utils', '__doc__': '\n Behaves exactly the same as a collections.defaultdict\n but works with pickle.loads. Fixes #10.\n ', '__weakref__': <attribute '__weakref__' of 'RecursiveDefaultDict' objects>})¶
-
__getitem__(key)¶
-
__init__(data=None)¶
-
__module__= 'chartit.utils'¶
-
__setitem__(key, item)¶
-
__weakref__¶ list of weak references to the object (if defined)
-
update(element)¶
-
-
chartit.utils._convert_to_rdd(obj)¶ Accepts a dict or a list of dicts and converts it to a RecursiveDefaultDict.
-
chartit.utils._getattr(obj, attr)¶ Recurses through an attribute chain to get the ultimate value.
chartit.validation module¶
Validates input parameters.
-
chartit.validation._clean_categories(categories, source)¶
-
chartit.validation._clean_field_aliases(fa_actual, fa_cat, fa_lgby)¶
-
chartit.validation._clean_legend_by(legend_by, source)¶
-
chartit.validation._clean_source(source)¶
-
chartit.validation._convert_cso_to_dict(series_options)¶
-
chartit.validation._convert_dps_to_dict(series_list)¶
-
chartit.validation._convert_pcso_to_dict(series_options)¶
-
chartit.validation._convert_pdps_to_dict(series_list)¶
-
chartit.validation._validate_field_lookup_term(model, term, query)¶ Checks whether the term is a valid field_lookup for the model.
Args:
- model (required) - a django model for which to check whether the term is a valid field_lookup.
- term (required) - the term to check whether it is a valid field lookup for the model supplied.
- query - the source query so we can check for aggregate or extra fields.
Returns:
- The verbose name of the field if the supplied term is a valid field.
Raises:
- APIInputError: If the term supplied is not a valid field lookup parameter for the model.
-
chartit.validation._validate_func(func)¶
-
chartit.validation._validate_top_n_per_cat(top_n_per_cat)¶
-
chartit.validation.clean_cso(series_options, ds)¶ Clean the Chart series_options input from the user.
-
chartit.validation.clean_dps(series)¶ Clean the DataPool series input from the user.
-
chartit.validation.clean_pcso(series_options, ds)¶ Clean the PivotChart series_options input from the user.
-
chartit.validation.clean_pdps(series)¶ Clean the PivotDataPool series input from the user.
-
chartit.validation.clean_sortf_mapf_mts(sortf_mapf_mts)¶
-
chartit.validation.clean_x_sortf_mapf_mts(x_sortf_mapf_mts)¶
-
chartit.validation.get_all_field_names(meta)¶ Taken from Django 1.9.8 b/c this is unofficial API which has been deprecated in 1.10.
Module contents¶
This Django application can be used to create charts and pivot charts directly from models.