From 0e2af186355d0516421141a2b80bae5bad6483f6 Mon Sep 17 00:00:00 2001 From: Jake VanderPlas Date: Tue, 20 Aug 2019 14:31:17 -0700 Subject: [PATCH 1/2] ENH: add alt.sequence() and alt.graticule() --- altair/vegalite/v3/api.py | 25 ++++++++++++++++++++++++- altair/vegalite/v3/tests/test_api.py | 19 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/altair/vegalite/v3/api.py b/altair/vegalite/v3/api.py index 44663262a..d148d3d81 100644 --- a/altair/vegalite/v3/api.py +++ b/altair/vegalite/v3/api.py @@ -93,7 +93,8 @@ def _prepare_data(data, context): # if data is still not a recognized type, then return if not isinstance(data, (dict, core.Data, core.UrlData, - core.InlineData, core.NamedData)): + core.InlineData, core.NamedData, + core.GraticuleGenerator, core.SequenceGenerator)): warnings.warn("data of type {} not recognized".format(type(data))) return data @@ -1962,3 +1963,25 @@ def remove_data(subchart): subcharts = [remove_data(c) for c in subcharts] return data, subcharts + + +@utils.use_signature(core.SequenceParams) +def sequence(start, stop=None, step=Undefined, as_=Undefined, **kwds): + """Sequence generator.""" + if stop is None: + start, stop = 0, start + params = core.SequenceParams( + start=start, stop=stop, step=step, **{'as': as_} + ) + return core.SequenceGenerator(sequence=params, **kwds) + + +@utils.use_signature(core.GraticuleParams) +def graticule(**kwds): + """Graticule generator.""" + if not kwds: + # graticule: True indicates default parameters + graticule = True + else: + graticule = core.GraticuleParams(**kwds) + return core.GraticuleGenerator(graticule=graticule) \ No newline at end of file diff --git a/altair/vegalite/v3/tests/test_api.py b/altair/vegalite/v3/tests/test_api.py index 60b8fb2e2..f556376d3 100644 --- a/altair/vegalite/v3/tests/test_api.py +++ b/altair/vegalite/v3/tests/test_api.py @@ -840,3 +840,22 @@ def test_facet(chart_type, facet_arg): assert dct['facet'] == expected else: assert dct['facet'][facet_arg] == expected + + +def test_sequence(): + data = alt.sequence(100) + assert data.to_dict() == {'sequence': {'start': 0, 'stop': 100}} + + data = alt.sequence(5, 10) + assert data.to_dict() == {'sequence': {'start': 5, 'stop': 10}} + + data = alt.sequence(0, 1, 0.1, as_='x') + assert data.to_dict() == {'sequence': {'start': 0, 'stop': 1, 'step': 0.1, 'as': 'x'}} + + +def test_graticule(): + data = alt.graticule() + assert data.to_dict() == {'graticule': True} + + data = alt.graticule(step=[15, 15]) + assert data.to_dict() == {'graticule': {'step': [15, 15]}} \ No newline at end of file From 5f4a0369e2793b06173237d5b8bd6de0d38349ef Mon Sep 17 00:00:00 2001 From: Jake VanderPlas Date: Tue, 20 Aug 2019 14:31:32 -0700 Subject: [PATCH 2/2] DOC: add documentation for data generators --- doc/user_guide/data.rst | 46 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/doc/user_guide/data.rst b/doc/user_guide/data.rst index 33dc1e485..d5e026043 100644 --- a/doc/user_guide/data.rst +++ b/doc/user_guide/data.rst @@ -229,6 +229,52 @@ With it, the above chart can be reproduced as follows: Notice that unlike the pandas ``melt`` function we must explicitly specify the columns to be folded. The ``as_`` argument is optional, with the default being ``["key", "value"]``. + +.. _data-generated: + +Generated Data +~~~~~~~~~~~~~~ +At times it is convenient to not use an external data source, but rather generate data for +display within the chart specification itself. The benefit is that the chart specification +can be made much smaller for generated data than for embedded data. + +Sequence Generator +^^^^^^^^^^^^^^^^^^ +Here is an example of using the :func:`sequence` function to generate a sequence of *x* +data, along with a :ref:`user-guide-calculate-transform` to compute *y* data. + +.. altair-plot:: + + import altair as alt + + # Note that the following generator is functionally similar to + # data = pd.DataFrame({'x': np.arange(0, 10, 0.1)}) + data = alt.sequence(0, 10, 0.1, as_='x') + + alt.Chart(data).transform_calculate( + y='sin(datum.x)' + ).mark_line().encode( + x='x:Q', + y='y:Q', + ) + +Graticule Generator +^^^^^^^^^^^^^^^^^^^ +Another type of data that is convenient to generate in the chart itself is the latitude/longitude +lines on a geographic visualization, known as a graticule. These can be created using Altair's +:func:`graticule` generator function. Here is a simple example: + +.. altair-plot:: + + import altair as alt + + data = alt.graticule(step=[15, 15]) + + alt.Chart(data).mark_geoshape().project( + 'orthographic', + rotate=[0, -45, 0] + ) + .. _Pandas: http://pandas.pydata.org/ .. _Pandas pivot documentation: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.pivot.html .. _Pandas melt documentation: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.melt.html#pandas.DataFrame.melt