From 3de1ba40fca02635e86f12bb512f4e48546b267a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Tue, 1 Nov 2022 18:24:59 +0100 Subject: [PATCH 01/45] feat: create `examples-vl` notebook We can delete this before merging, but the nb should be useful for discussions --- docs/facts/examples-vl.ipynb | 1941 ++++++++++++++++++++++++++++++++++ 1 file changed, 1941 insertions(+) create mode 100644 docs/facts/examples-vl.ipynb diff --git a/docs/facts/examples-vl.ipynb b/docs/facts/examples-vl.ipynb new file mode 100644 index 00000000..25235fd0 --- /dev/null +++ b/docs/facts/examples-vl.ipynb @@ -0,0 +1,1941 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Example Charts\n", + "\n", + "This notebook recreates the examples from [https://dig.cmu.edu/draco2/facts/examples.html#](https://dig.cmu.edu/draco2/facts/examples.html#)." + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [], + "source": [ + "from pprint import pprint\n", + "from draco.fact_utils import answer_set_to_dict\n", + "from draco.run import run_clingo\n", + "import altair as alt\n", + "from altair import datum" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [], + "source": [ + "def facts_to_dict(facts: list[str]):\n", + " result = run_clingo(facts)\n", + " return answer_set_to_dict(next(result).answer_set)" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [], + "source": [ + "from IPython.display import display\n", + "import json\n", + "\n", + "def display_chart(chart: alt.Chart):\n", + " dct = json.loads(chart.to_json())\n", + " dct.pop('data')\n", + " dct.pop('datasets')\n", + " pprint(dct)\n", + " display(chart)" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import random\n", + "\n", + "# Generate a random dataframe with the following columns:\n", + "# - temperature: a random float between -10 and 44\n", + "# - wind: a random float between 0 and 100\n", + "# - precipitation: a random float between 0 and 100\n", + "# - condition: a random string from the list [\"drizzle\", \"fog\", \"rain\", \"sun\", \"snow\"]\n", + "NUM_ROWS = 100\n", + "df = pd.DataFrame(\n", + " {\n", + " \"temperature\": [random.uniform(-10, 44) for _ in range(NUM_ROWS)],\n", + " \"wind\": [random.uniform(0, 100) for _ in range(NUM_ROWS)],\n", + " \"precipitation\": [random.uniform(0, 100) for _ in range(NUM_ROWS)],\n", + " \"condition\": [random.choice([\"drizzle\", \"fog\", \"rain\", \"sun\", \"snow\"]) for _ in range(NUM_ROWS)],\n", + " }\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": " temperature wind precipitation condition\n0 39.357872 11.562264 88.420514 fog\n1 -5.947155 86.907017 70.558329 rain\n2 32.827656 97.658974 82.655115 sun\n3 17.525999 65.527975 53.862565 snow\n4 -6.808827 37.034294 93.865255 drizzle", + "text/html": "
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
temperaturewindprecipitationcondition
039.35787211.56226488.420514fog
1-5.94715586.90701770.558329rain
232.82765697.65897482.655115sun
317.52599965.52797553.862565snow
4-6.80882737.03429493.865255drizzle
\n
" + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Single View, Single Mark Charts" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Tick Plot" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'field': [{'name': 'temperature', 'type': 'number'}],\n", + " 'number_rows': 100,\n", + " 'view': [{'mark': [{'encoding': [{'channel': 'x', 'field': 'temperature'}],\n", + " 'type': 'tick'}],\n", + " 'scale': [{'channel': 'x', 'type': 'linear'}]}]}\n" + ] + } + ], + "source": [ + "facts = ['attribute(number_rows,root,100).',\n", + " 'entity(field,root,temperature).',\n", + " 'attribute((field,name),temperature,temperature).',\n", + " 'attribute((field,type),temperature,number).',\n", + " 'entity(view,root,0).',\n", + " 'entity(mark,0,1).',\n", + " 'attribute((mark,type),1,tick).',\n", + " 'entity(encoding,1,2).',\n", + " 'attribute((encoding,channel),2,x).',\n", + " 'attribute((encoding,field),2,temperature).',\n", + " 'entity(scale,0,3).',\n", + " 'attribute((scale,channel),3,x).',\n", + " 'attribute((scale,type),3,linear).']\n", + "spec = facts_to_dict(facts)\n", + "pprint(spec)" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", + " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", + " 'encoding': {'x': {'field': 'temperature',\n", + " 'scale': {'type': 'linear'},\n", + " 'type': 'quantitative'}},\n", + " 'mark': 'tick'}\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/petergy/Library/Caches/pypoetry/virtualenvs/draco-q9RTEhXP-py3.10/lib/python3.10/site-packages/altair/utils/core.py:317: FutureWarning: iteritems is deprecated and will be removed in a future version. Use .items instead.\n", + " for col_name, dtype in df.dtypes.iteritems():\n" + ] + }, + { + "data": { + "text/html": "\n
\n", + "text/plain": "alt.Chart(...)" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "base = alt.Chart(df)\n", + "tick = base.mark_tick().encode(\n", + " x=alt.X(field='temperature', type='quantitative', scale=alt.Scale(type='linear'))\n", + ")\n", + "display_chart(tick)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Tick Plot with a Log Scale" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'field': [{'name': 'temperature', 'type': 'number'}],\n", + " 'number_rows': 100,\n", + " 'view': [{'mark': [{'encoding': [{'channel': 'x', 'field': 'temperature'}],\n", + " 'type': 'tick'}],\n", + " 'scale': [{'channel': 'x', 'type': 'log'}]}]}\n" + ] + } + ], + "source": [ + "facts = ['attribute(number_rows,root,100).',\n", + " 'entity(field,root,temperature).',\n", + " 'attribute((field,name),temperature,temperature).',\n", + " 'attribute((field,type),temperature,number).',\n", + " 'entity(view,root,0).',\n", + " 'entity(mark,0,1).',\n", + " 'attribute((mark,type),1,tick).',\n", + " 'entity(encoding,1,2).',\n", + " 'attribute((encoding,channel),2,x).',\n", + " 'attribute((encoding,field),2,temperature).',\n", + " 'entity(scale,0,3).',\n", + " 'attribute((scale,channel),3,x).',\n", + " 'attribute((scale,type),3,log).']\n", + "spec = facts_to_dict(facts)\n", + "pprint(spec)" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", + " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", + " 'encoding': {'x': {'field': 'temperature',\n", + " 'scale': {'type': 'log'},\n", + " 'type': 'quantitative'}},\n", + " 'mark': 'tick',\n", + " 'transform': [{'filter': '(datum.temperature > 0)'}]}\n" + ] + }, + { + "data": { + "text/html": "\n
\n", + "text/plain": "alt.Chart(...)" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "base = alt.Chart(df).transform_filter(\n", + " datum.temperature > 0\n", + ")\n", + "tick = base.mark_tick().encode(\n", + " x=alt.X(field='temperature', type='quantitative', scale=alt.Scale(type='log'))\n", + ")\n", + "display_chart(tick)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Bar Chart" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'field': [{'name': 'temperature', 'type': 'number'},\n", + " {'name': 'condition', 'type': 'string'}],\n", + " 'number_rows': 100,\n", + " 'view': [{'coordinates': 'cartesian',\n", + " 'mark': [{'encoding': [{'channel': 'x', 'field': 'condition'},\n", + " {'aggregate': 'mean',\n", + " 'channel': 'y',\n", + " 'field': 'temperature'}],\n", + " 'type': 'bar'}],\n", + " 'scale': [{'channel': 'x', 'type': 'ordinal'},\n", + " {'channel': 'y', 'type': 'linear', 'zero': 'true'}]}]}\n" + ] + } + ], + "source": [ + "facts = ['attribute(number_rows,root,100).',\n", + " 'entity(field,root,temperature).',\n", + " 'attribute((field,name),temperature,temperature).',\n", + " 'attribute((field,type),temperature,number).',\n", + " 'entity(field,root,condition).',\n", + " 'attribute((field,name),condition,condition).',\n", + " 'attribute((field,type),condition,string).',\n", + " 'entity(view,root,0).',\n", + " 'attribute((view,coordinates),0,cartesian).',\n", + " 'entity(mark,0,1).',\n", + " 'attribute((mark,type),1,bar).',\n", + " 'entity(encoding,1,2).',\n", + " 'attribute((encoding,channel),2,x).',\n", + " 'attribute((encoding,field),2,condition).',\n", + " 'entity(encoding,1,3).',\n", + " 'attribute((encoding,channel),3,y).',\n", + " 'attribute((encoding,field),3,temperature).',\n", + " 'attribute((encoding,aggregate),3,mean).',\n", + " 'entity(scale,0,4).',\n", + " 'attribute((scale,channel),4,x).',\n", + " 'attribute((scale,type),4,ordinal).',\n", + " 'entity(scale,0,5).',\n", + " 'attribute((scale,channel),5,y).',\n", + " 'attribute((scale,type),5,linear).',\n", + " 'attribute((scale,zero),5,true).']\n", + "spec = facts_to_dict(facts)\n", + "pprint(spec)" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", + " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", + " 'encoding': {'x': {'field': 'condition',\n", + " 'scale': {'type': 'ordinal'},\n", + " 'type': 'nominal'},\n", + " 'y': {'aggregate': 'mean',\n", + " 'field': 'temperature',\n", + " 'scale': {'type': 'linear', 'zero': True},\n", + " 'type': 'quantitative'}},\n", + " 'mark': 'bar'}\n" + ] + }, + { + "data": { + "text/html": "\n
\n", + "text/plain": "alt.Chart(...)" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "base = alt.Chart(df)\n", + "bar = base.mark_bar().encode(\n", + " x=alt.X(field='condition', \n", + " type='nominal', \n", + " scale=alt.Scale(type='ordinal')),\n", + " y=alt.Y(field='temperature', \n", + " type='quantitative', \n", + " aggregate='mean', \n", + " scale=alt.Scale(type='linear', zero=True))\n", + ")\n", + "display_chart(bar)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Radial Chart" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'field': [{'name': 'temperature', 'type': 'number'},\n", + " {'name': 'condition', 'type': 'string'}],\n", + " 'number_rows': 100,\n", + " 'view': [{'coordinates': 'polar',\n", + " 'mark': [{'encoding': [{'channel': 'x', 'field': 'condition'},\n", + " {'aggregate': 'mean',\n", + " 'channel': 'y',\n", + " 'field': 'temperature'}],\n", + " 'type': 'bar'}],\n", + " 'scale': [{'channel': 'x', 'type': 'ordinal'},\n", + " {'channel': 'y', 'type': 'linear', 'zero': 'true'}]}]}\n" + ] + } + ], + "source": [ + "facts = ['attribute(number_rows,root,100).',\n", + " 'entity(field,root,temperature).',\n", + " 'attribute((field,name),temperature,temperature).',\n", + " 'attribute((field,type),temperature,number).',\n", + " 'entity(field,root,condition).',\n", + " 'attribute((field,name),condition,condition).',\n", + " 'attribute((field,type),condition,string).',\n", + " 'entity(view,root,0).',\n", + " 'attribute((view,coordinates),0,polar).',\n", + " 'entity(mark,0,1).',\n", + " 'attribute((mark,type),1,bar).',\n", + " 'entity(encoding,1,2).',\n", + " 'attribute((encoding,channel),2,x).',\n", + " 'attribute((encoding,field),2,condition).',\n", + " 'entity(encoding,1,3).',\n", + " 'attribute((encoding,channel),3,y).',\n", + " 'attribute((encoding,field),3,temperature).',\n", + " 'attribute((encoding,aggregate),3,mean).',\n", + " 'entity(scale,0,4).',\n", + " 'attribute((scale,channel),4,x).',\n", + " 'attribute((scale,type),4,ordinal).',\n", + " 'entity(scale,0,5).',\n", + " 'attribute((scale,channel),5,y).',\n", + " 'attribute((scale,type),5,linear).',\n", + " 'attribute((scale,zero),5,true).']\n", + "spec = facts_to_dict(facts)\n", + "pprint(spec)" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", + " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", + " 'layer': [{'encoding': {'radius': {'aggregate': 'mean',\n", + " 'field': 'temperature',\n", + " 'type': 'quantitative'},\n", + " 'theta': {'field': 'condition', 'type': 'nominal'}},\n", + " 'mark': {'stroke': '#ffffff', 'type': 'arc'}},\n", + " {'encoding': {'radius': {'aggregate': 'mean',\n", + " 'field': 'temperature',\n", + " 'type': 'quantitative'},\n", + " 'text': {'field': 'condition', 'type': 'nominal'},\n", + " 'theta': {'field': 'condition', 'type': 'nominal'}},\n", + " 'mark': {'radiusOffset': 15, 'type': 'text'}}]}\n" + ] + }, + { + "data": { + "text/html": "\n
\n", + "text/plain": "alt.LayerChart(...)" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "base = alt.Chart(df)\n", + "arc = base.mark_arc(stroke='#ffffff').encode(\n", + " theta=alt.Theta(field='condition', type='nominal'),\n", + " radius=alt.Radius(field='temperature', type='quantitative', aggregate='mean')\n", + ")\n", + "text = base.mark_text(radiusOffset=15).encode(\n", + " theta=alt.Theta(field='condition', type='nominal'),\n", + " radius=alt.Radius(field='temperature', type='quantitative', aggregate='mean'),\n", + " text=alt.Text(field='condition', type='nominal')\n", + ")\n", + "display_chart(arc + text)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Histogram" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'field': [{'name': 'condition', 'type': 'string'}],\n", + " 'number_rows': 100,\n", + " 'view': [{'mark': [{'encoding': [{'channel': 'x', 'field': 'condition'},\n", + " {'aggregate': 'count', 'channel': 'y'}],\n", + " 'type': 'bar'}],\n", + " 'scale': [{'channel': 'x', 'type': 'ordinal'},\n", + " {'channel': 'y', 'type': 'linear', 'zero': 'true'}]}]}\n" + ] + } + ], + "source": [ + "facts = ['attribute(number_rows,root,100).',\n", + " 'entity(field,root,condition).',\n", + " 'attribute((field,name),condition,condition).',\n", + " 'attribute((field,type),condition,string).',\n", + " 'entity(view,root,0).',\n", + " 'entity(mark,0,1).',\n", + " 'attribute((mark,type),1,bar).',\n", + " 'entity(encoding,1,2).',\n", + " 'attribute((encoding,channel),2,x).',\n", + " 'attribute((encoding,field),2,condition).',\n", + " 'entity(encoding,1,3).',\n", + " 'attribute((encoding,channel),3,y).',\n", + " 'attribute((encoding,aggregate),3,count).',\n", + " 'entity(scale,0,4).',\n", + " 'attribute((scale,channel),4,x).',\n", + " 'attribute((scale,type),4,ordinal).',\n", + " 'entity(scale,0,5).',\n", + " 'attribute((scale,channel),5,y).',\n", + " 'attribute((scale,type),5,linear).',\n", + " 'attribute((scale,zero),5,true).']\n", + "spec = facts_to_dict(facts)\n", + "pprint(spec)" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", + " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", + " 'encoding': {'x': {'field': 'condition',\n", + " 'scale': {'type': 'ordinal'},\n", + " 'type': 'nominal'},\n", + " 'y': {'aggregate': 'count',\n", + " 'field': 'condition',\n", + " 'scale': {'type': 'linear', 'zero': True},\n", + " 'type': 'nominal'}},\n", + " 'mark': 'bar'}\n" + ] + }, + { + "data": { + "text/html": "\n
\n", + "text/plain": "alt.Chart(...)" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "base = alt.Chart(df)\n", + "bar = base.mark_bar().encode(\n", + " x=alt.X(field='condition', \n", + " type='nominal', \n", + " scale=alt.Scale(type='ordinal')),\n", + " y=alt.Y(field='condition', \n", + " type='nominal', \n", + " aggregate='count', \n", + " scale=alt.Scale(type='linear', zero=True))\n", + ")\n", + "display_chart(bar)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Binned Histrogram" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'field': [{'name': 'temperature', 'type': 'number'}],\n", + " 'number_rows': 100,\n", + " 'view': [{'mark': [{'encoding': [{'binning': 10,\n", + " 'channel': 'x',\n", + " 'field': 'temperature'},\n", + " {'aggregate': 'count', 'channel': 'y'}],\n", + " 'type': 'bar'}],\n", + " 'scale': [{'channel': 'x', 'type': 'linear'},\n", + " {'channel': 'y', 'type': 'linear', 'zero': 'true'}]}]}\n" + ] + } + ], + "source": [ + "facts = ['attribute(number_rows,root,100).',\n", + " 'entity(field,root,temperature).',\n", + " 'attribute((field,name),temperature,temperature).',\n", + " 'attribute((field,type),temperature,number).',\n", + " 'entity(view,root,0).',\n", + " 'entity(mark,0,1).',\n", + " 'attribute((mark,type),1,bar).',\n", + " 'entity(encoding,1,2).',\n", + " 'attribute((encoding,channel),2,x).',\n", + " 'attribute((encoding,field),2,temperature).',\n", + " 'attribute((encoding,binning),2,10).',\n", + " 'entity(encoding,1,3).',\n", + " 'attribute((encoding,channel),3,y).',\n", + " 'attribute((encoding,aggregate),3,count).',\n", + " 'entity(scale,0,4).',\n", + " 'attribute((scale,channel),4,x).',\n", + " 'attribute((scale,type),4,linear).',\n", + " 'entity(scale,0,5).',\n", + " 'attribute((scale,channel),5,y).',\n", + " 'attribute((scale,type),5,linear).',\n", + " 'attribute((scale,zero),5,true).']\n", + "spec = facts_to_dict(facts)\n", + "pprint(spec)" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", + " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", + " 'encoding': {'x': {'bin': {'maxbins': 10},\n", + " 'field': 'temperature',\n", + " 'scale': {'type': 'linear'},\n", + " 'type': 'quantitative'},\n", + " 'y': {'aggregate': 'count',\n", + " 'field': 'temperature',\n", + " 'scale': {'type': 'linear', 'zero': True},\n", + " 'type': 'quantitative'}},\n", + " 'mark': 'bar'}\n" + ] + }, + { + "data": { + "text/html": "\n
\n", + "text/plain": "alt.Chart(...)" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "base = alt.Chart(df)\n", + "bar = base.mark_bar().encode(\n", + " x=alt.X(field='temperature', \n", + " type='quantitative',\n", + " bin=alt.Bin(maxbins=10),\n", + " scale=alt.Scale(type='linear')),\n", + " y=alt.Y(field='temperature', \n", + " type='quantitative', \n", + " aggregate='count', \n", + " scale=alt.Scale(type='linear', zero=True))\n", + ")\n", + "display_chart(bar)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Scatterplot" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'field': [{'name': 'temperature', 'type': 'number'},\n", + " {'name': 'wind', 'type': 'number'}],\n", + " 'number_rows': 100,\n", + " 'view': [{'mark': [{'encoding': [{'channel': 'x', 'field': 'temperature'},\n", + " {'channel': 'y', 'field': 'wind'}],\n", + " 'type': 'point'}],\n", + " 'scale': [{'channel': 'x', 'type': 'linear'},\n", + " {'channel': 'y', 'type': 'linear'}]}]}\n" + ] + } + ], + "source": [ + "facts = ['attribute(number_rows,root,100).',\n", + " 'entity(field,root,temperature).',\n", + " 'attribute((field,name),temperature,temperature).',\n", + " 'attribute((field,type),temperature,number).',\n", + " 'entity(field,root,wind).',\n", + " 'attribute((field,name),wind,wind).',\n", + " 'attribute((field,type),wind,number).',\n", + " 'entity(view,root,0).',\n", + " 'entity(mark,0,1).',\n", + " 'attribute((mark,type),1,point).',\n", + " 'entity(encoding,1,2).',\n", + " 'attribute((encoding,channel),2,x).',\n", + " 'attribute((encoding,field),2,temperature).',\n", + " 'entity(encoding,1,3).',\n", + " 'attribute((encoding,channel),3,y).',\n", + " 'attribute((encoding,field),3,wind).',\n", + " 'entity(scale,0,4).',\n", + " 'attribute((scale,channel),4,x).',\n", + " 'attribute((scale,type),4,linear).',\n", + " 'entity(scale,0,5).',\n", + " 'attribute((scale,channel),5,y).',\n", + " 'attribute((scale,type),5,linear).']\n", + "spec = facts_to_dict(facts)\n", + "pprint(spec)" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", + " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", + " 'encoding': {'x': {'field': 'temperature',\n", + " 'scale': {'type': 'linear'},\n", + " 'type': 'quantitative'},\n", + " 'y': {'field': 'wind',\n", + " 'scale': {'type': 'linear'},\n", + " 'type': 'quantitative'}},\n", + " 'mark': 'point'}\n" + ] + }, + { + "data": { + "text/html": "\n
\n", + "text/plain": "alt.Chart(...)" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "base = alt.Chart(df)\n", + "point = base.mark_point().encode(\n", + " x=alt.X(field='temperature', \n", + " type='quantitative', \n", + " scale=alt.Scale(type='linear')),\n", + " y=alt.Y(field='wind',\n", + " type='quantitative', \n", + " scale=alt.Scale(type='linear')),\n", + ")\n", + "display_chart(point)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Scatterplot with Color" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'field': [{'name': 'temperature', 'type': 'number'},\n", + " {'name': 'wind', 'type': 'number'},\n", + " {'name': 'condition', 'type': 'string'}],\n", + " 'number_rows': 100,\n", + " 'view': [{'mark': [{'encoding': [{'channel': 'x', 'field': 'temperature'},\n", + " {'channel': 'y', 'field': 'wind'},\n", + " {'channel': 'color', 'field': 'condition'}],\n", + " 'type': 'point'}],\n", + " 'scale': [{'channel': 'x', 'type': 'linear'},\n", + " {'channel': 'y', 'type': 'linear'},\n", + " {'channel': 'color', 'type': 'categorical'}]}]}\n" + ] + } + ], + "source": [ + "facts = ['attribute(number_rows,root,100).',\n", + " 'entity(field,root,temperature).',\n", + " 'attribute((field,name),temperature,temperature).',\n", + " 'attribute((field,type),temperature,number).',\n", + " 'entity(field,root,wind).',\n", + " 'attribute((field,name),wind,wind).',\n", + " 'attribute((field,type),wind,number).',\n", + " 'entity(field,root,condition).',\n", + " 'attribute((field,name),condition,condition).',\n", + " 'attribute((field,type),condition,string).',\n", + " 'entity(view,root,0).',\n", + " 'entity(mark,0,1).',\n", + " 'attribute((mark,type),1,point).',\n", + " 'entity(encoding,1,2).',\n", + " 'attribute((encoding,channel),2,x).',\n", + " 'attribute((encoding,field),2,temperature).',\n", + " 'entity(encoding,1,3).',\n", + " 'attribute((encoding,channel),3,y).',\n", + " 'attribute((encoding,field),3,wind).',\n", + " 'entity(encoding,1,4).',\n", + " 'attribute((encoding,channel),4,color).',\n", + " 'attribute((encoding,field),4,condition).',\n", + " 'entity(scale,0,5).',\n", + " 'attribute((scale,channel),5,x).',\n", + " 'attribute((scale,type),5,linear).',\n", + " 'entity(scale,0,6).',\n", + " 'attribute((scale,channel),6,y).',\n", + " 'attribute((scale,type),6,linear).',\n", + " 'entity(scale,0,7).',\n", + " 'attribute((scale,channel),7,color).',\n", + " 'attribute((scale,type),7,categorical).']\n", + "spec = facts_to_dict(facts)\n", + "pprint(spec)" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", + " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", + " 'encoding': {'color': {'field': 'condition',\n", + " 'scale': {'type': 'ordinal'},\n", + " 'type': 'nominal'},\n", + " 'x': {'field': 'temperature',\n", + " 'scale': {'type': 'linear'},\n", + " 'type': 'quantitative'},\n", + " 'y': {'field': 'wind',\n", + " 'scale': {'type': 'linear'},\n", + " 'type': 'quantitative'}},\n", + " 'mark': 'point'}\n" + ] + }, + { + "data": { + "text/html": "\n
\n", + "text/plain": "alt.Chart(...)" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "base = alt.Chart(df)\n", + "point = base.mark_point().encode(\n", + " x=alt.X(field='temperature', \n", + " type='quantitative', \n", + " scale=alt.Scale(type='linear')),\n", + " y=alt.Y(field='wind',\n", + " type='quantitative', \n", + " scale=alt.Scale(type='linear')),\n", + " color=alt.Color(field='condition',\n", + " type='nominal',\n", + " scale=alt.Scale(type='ordinal'))\n", + ")\n", + "display_chart(point)" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'field': [{'name': 'temperature', 'type': 'number'},\n", + " {'name': 'wind', 'type': 'number'},\n", + " {'name': 'precipitation', 'type': 'number'}],\n", + " 'number_rows': 100,\n", + " 'view': [{'mark': [{'encoding': [{'channel': 'x', 'field': 'temperature'},\n", + " {'channel': 'y', 'field': 'wind'},\n", + " {'channel': 'size',\n", + " 'field': 'precipitation'}],\n", + " 'type': 'point'}],\n", + " 'scale': [{'channel': 'x', 'type': 'linear'},\n", + " {'channel': 'y', 'type': 'linear'},\n", + " {'channel': 'size', 'type': 'linear'}]}]}\n" + ] + } + ], + "source": [ + "facts = ['attribute(number_rows,root,100).',\n", + " 'entity(field,root,temperature).',\n", + " 'attribute((field,name),temperature,temperature).',\n", + " 'attribute((field,type),temperature,number).',\n", + " 'entity(field,root,wind).',\n", + " 'attribute((field,name),wind,wind).',\n", + " 'attribute((field,type),wind,number).',\n", + " 'entity(field,root,precipitation).',\n", + " 'attribute((field,name),precipitation,precipitation).',\n", + " 'attribute((field,type),precipitation,number).',\n", + " 'entity(view,root,0).',\n", + " 'entity(mark,0,1).',\n", + " 'attribute((mark,type),1,point).',\n", + " 'entity(encoding,1,2).',\n", + " 'attribute((encoding,channel),2,x).',\n", + " 'attribute((encoding,field),2,temperature).',\n", + " 'entity(encoding,1,3).',\n", + " 'attribute((encoding,channel),3,y).',\n", + " 'attribute((encoding,field),3,wind).',\n", + " 'entity(encoding,1,4).',\n", + " 'attribute((encoding,channel),4,size).',\n", + " 'attribute((encoding,field),4,precipitation).',\n", + " 'entity(scale,0,5).',\n", + " 'attribute((scale,channel),5,x).',\n", + " 'attribute((scale,type),5,linear).',\n", + " 'entity(scale,0,6).',\n", + " 'attribute((scale,channel),6,y).',\n", + " 'attribute((scale,type),6,linear).',\n", + " 'entity(scale,0,7).',\n", + " 'attribute((scale,channel),7,size).',\n", + " 'attribute((scale,type),7,linear).']\n", + "spec = facts_to_dict(facts)\n", + "pprint(spec)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Bubble Chart" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", + " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", + " 'encoding': {'size': {'field': 'precipitation',\n", + " 'scale': {'type': 'linear'},\n", + " 'type': 'quantitative'},\n", + " 'x': {'field': 'temperature',\n", + " 'scale': {'type': 'linear'},\n", + " 'type': 'quantitative'},\n", + " 'y': {'field': 'wind',\n", + " 'scale': {'type': 'linear'},\n", + " 'type': 'quantitative'}},\n", + " 'mark': 'point'}\n" + ] + }, + { + "data": { + "text/html": "\n
\n", + "text/plain": "alt.Chart(...)" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "base = alt.Chart(df)\n", + "point = base.mark_point().encode(\n", + " x=alt.X(field='temperature', \n", + " type='quantitative', \n", + " scale=alt.Scale(type='linear')),\n", + " y=alt.Y(field='wind',\n", + " type='quantitative', \n", + " scale=alt.Scale(type='linear')),\n", + " size=alt.Size(field='precipitation', \n", + " type='quantitative', \n", + " scale=alt.Scale(type='linear')),\n", + ")\n", + "display_chart(point)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Stacked Charts" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Pie Chart" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'field': [{'name': 'temperature', 'type': 'number'},\n", + " {'name': 'condition', 'type': 'string'}],\n", + " 'number_rows': 100,\n", + " 'view': [{'coordinates': 'polar',\n", + " 'mark': [{'encoding': [{'aggregate': 'count',\n", + " 'channel': 'y',\n", + " 'stack': 'zero'},\n", + " {'channel': 'color', 'field': 'condition'}],\n", + " 'type': 'bar'}],\n", + " 'scale': [{'channel': 'y', 'type': 'linear', 'zero': 'true'},\n", + " {'channel': 'color', 'type': 'categorical'}]}]}\n" + ] + } + ], + "source": [ + "facts = ['attribute(number_rows,root,100).',\n", + " 'entity(field,root,temperature).',\n", + " 'attribute((field,name),temperature,temperature).',\n", + " 'attribute((field,type),temperature,number).',\n", + " 'entity(field,root,condition).',\n", + " 'attribute((field,name),condition,condition).',\n", + " 'attribute((field,type),condition,string).',\n", + " 'entity(view,root,0).',\n", + " 'attribute((view,coordinates),0,polar).',\n", + " 'entity(mark,0,1).',\n", + " 'attribute((mark,type),1,bar).',\n", + " 'entity(encoding,1,2).',\n", + " 'attribute((encoding,channel),2,y).',\n", + " 'attribute((encoding,aggregate),2,count).',\n", + " 'attribute((encoding,stack),2,zero).',\n", + " 'entity(encoding,1,3).',\n", + " 'attribute((encoding,channel),3,color).',\n", + " 'attribute((encoding,field),3,condition).',\n", + " 'entity(scale,0,4).',\n", + " 'attribute((scale,channel),4,y).',\n", + " 'attribute((scale,type),4,linear).',\n", + " 'attribute((scale,zero),4,true).',\n", + " 'entity(scale,0,5).',\n", + " 'attribute((scale,channel),5,color).',\n", + " 'attribute((scale,type),5,categorical).']\n", + "spec = facts_to_dict(facts)\n", + "pprint(spec)" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", + " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", + " 'encoding': {'color': {'field': 'condition',\n", + " 'scale': {'type': 'ordinal'},\n", + " 'type': 'nominal'},\n", + " 'theta': {'aggregate': 'count',\n", + " 'field': 'temperature',\n", + " 'scale': {'type': 'linear', 'zero': True},\n", + " 'stack': 'zero',\n", + " 'type': 'quantitative'}},\n", + " 'mark': 'arc'}\n" + ] + }, + { + "data": { + "text/html": "\n
\n", + "text/plain": "alt.Chart(...)" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "base = alt.Chart(df)\n", + "arc = base.mark_arc().encode(\n", + " theta=alt.Theta(field='temperature', \n", + " type='quantitative', \n", + " aggregate='count',\n", + " stack='zero',\n", + " scale=alt.Scale(type='linear', zero=True)),\n", + " color=alt.Color(field='condition', \n", + " type='nominal',\n", + " scale=alt.Scale(type='ordinal')),\n", + ")\n", + "display_chart(arc)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Stacked Bar Chart" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'field': [{'name': 'temperature', 'type': 'number'},\n", + " {'name': 'condition', 'type': 'string'}],\n", + " 'number_rows': 100,\n", + " 'view': [{'mark': [{'encoding': [{'binning': 10,\n", + " 'channel': 'x',\n", + " 'field': 'temperature'},\n", + " {'aggregate': 'count',\n", + " 'channel': 'y',\n", + " 'stack': 'zero'},\n", + " {'channel': 'color', 'field': 'condition'}],\n", + " 'type': 'bar'}],\n", + " 'scale': [{'channel': 'x', 'type': 'linear'},\n", + " {'channel': 'y', 'type': 'linear', 'zero': 'true'},\n", + " {'channel': 'color', 'type': 'categorical'}]}]}\n" + ] + } + ], + "source": [ + "facts = ['attribute(number_rows,root,100).',\n", + " 'entity(field,root,temperature).',\n", + " 'attribute((field,name),temperature,temperature).',\n", + " 'attribute((field,type),temperature,number).',\n", + " 'entity(field,root,condition).',\n", + " 'attribute((field,name),condition,condition).',\n", + " 'attribute((field,type),condition,string).',\n", + " 'entity(view,root,0).',\n", + " 'entity(mark,0,1).',\n", + " 'attribute((mark,type),1,bar).',\n", + " 'entity(encoding,1,2).',\n", + " 'attribute((encoding,channel),2,x).',\n", + " 'attribute((encoding,field),2,temperature).',\n", + " 'attribute((encoding,binning),2,10).',\n", + " 'entity(encoding,1,3).',\n", + " 'attribute((encoding,channel),3,y).',\n", + " 'attribute((encoding,aggregate),3,count).',\n", + " 'attribute((encoding,stack),3,zero).',\n", + " 'entity(encoding,1,4).',\n", + " 'attribute((encoding,channel),4,color).',\n", + " 'attribute((encoding,field),4,condition).',\n", + " 'entity(scale,0,5).',\n", + " 'attribute((scale,channel),5,x).',\n", + " 'attribute((scale,type),5,linear).',\n", + " 'entity(scale,0,6).',\n", + " 'attribute((scale,channel),6,y).',\n", + " 'attribute((scale,type),6,linear).',\n", + " 'attribute((scale,zero),6,true).',\n", + " 'entity(scale,0,7).',\n", + " 'attribute((scale,channel),7,color).',\n", + " 'attribute((scale,type),7,categorical).']\n", + "spec = facts_to_dict(facts)\n", + "pprint(spec)" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", + " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", + " 'encoding': {'color': {'field': 'condition', 'type': 'nominal'},\n", + " 'x': {'bin': {'maxbins': 10},\n", + " 'field': 'temperature',\n", + " 'scale': {'type': 'linear'},\n", + " 'type': 'quantitative'},\n", + " 'y': {'aggregate': 'count',\n", + " 'field': 'temperature',\n", + " 'scale': {'type': 'linear', 'zero': True},\n", + " 'stack': 'zero',\n", + " 'type': 'quantitative'}},\n", + " 'mark': 'bar'}\n" + ] + }, + { + "data": { + "text/html": "\n
\n", + "text/plain": "alt.Chart(...)" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "base = alt.Chart(df)\n", + "bar = base.mark_bar().encode(\n", + " x=alt.X(field='temperature', \n", + " type='quantitative',\n", + " bin=alt.Bin(maxbins=10),\n", + " scale=alt.Scale(type='linear')),\n", + " y=alt.Y(field='temperature', \n", + " type='quantitative', \n", + " aggregate='count',\n", + " stack='zero',\n", + " scale=alt.Scale(type='linear', zero=True)),\n", + " color=alt.Color(field='condition', type='nominal')\n", + ")\n", + "display_chart(bar)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Normalized (Percentage) Stacked Bar Chart" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'field': [{'name': 'temperature', 'type': 'number'},\n", + " {'name': 'condition', 'type': 'string'}],\n", + " 'number_rows': 100,\n", + " 'view': [{'mark': [{'encoding': [{'aggregate': 'count',\n", + " 'channel': 'x',\n", + " 'stack': 'normalize'},\n", + " {'binning': 10,\n", + " 'channel': 'y',\n", + " 'field': 'temperature'},\n", + " {'channel': 'color', 'field': 'condition'}],\n", + " 'type': 'bar'}],\n", + " 'scale': [{'channel': 'x', 'type': 'linear', 'zero': 'true'},\n", + " {'channel': 'y', 'type': 'linear'},\n", + " {'channel': 'color', 'type': 'categorical'}]}]}\n" + ] + } + ], + "source": [ + "facts = ['attribute(number_rows,root,100).',\n", + " 'entity(field,root,temperature).',\n", + " 'attribute((field,name),temperature,temperature).',\n", + " 'attribute((field,type),temperature,number).',\n", + " 'entity(field,root,condition).',\n", + " 'attribute((field,name),condition,condition).',\n", + " 'attribute((field,type),condition,string).',\n", + " 'entity(view,root,0).',\n", + " 'entity(mark,0,1).',\n", + " 'attribute((mark,type),1,bar).',\n", + " 'entity(encoding,1,2).',\n", + " 'attribute((encoding,channel),2,x).',\n", + " 'attribute((encoding,aggregate),2,count).',\n", + " 'attribute((encoding,stack),2,normalize).',\n", + " 'entity(encoding,1,3).',\n", + " 'attribute((encoding,channel),3,y).',\n", + " 'attribute((encoding,field),3,temperature).',\n", + " 'attribute((encoding,binning),3,10).',\n", + " 'entity(encoding,1,4).',\n", + " 'attribute((encoding,channel),4,color).',\n", + " 'attribute((encoding,field),4,condition).',\n", + " 'entity(scale,0,5).',\n", + " 'attribute((scale,channel),5,x).',\n", + " 'attribute((scale,type),5,linear).',\n", + " 'attribute((scale,zero),5,true).',\n", + " 'entity(scale,0,6).',\n", + " 'attribute((scale,channel),6,y).',\n", + " 'attribute((scale,type),6,linear).',\n", + " 'entity(scale,0,7).',\n", + " 'attribute((scale,channel),7,color).',\n", + " 'attribute((scale,type),7,categorical).']\n", + "spec = facts_to_dict(facts)\n", + "pprint(spec)" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", + " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", + " 'encoding': {'color': {'field': 'condition', 'type': 'nominal'},\n", + " 'x': {'aggregate': 'count',\n", + " 'field': 'temperature',\n", + " 'scale': {'type': 'linear', 'zero': True},\n", + " 'stack': 'normalize',\n", + " 'type': 'quantitative'},\n", + " 'y': {'bin': {'maxbins': 10},\n", + " 'field': 'temperature',\n", + " 'scale': {'type': 'linear'},\n", + " 'type': 'quantitative'}},\n", + " 'mark': 'bar'}\n" + ] + }, + { + "data": { + "text/html": "\n
\n", + "text/plain": "alt.Chart(...)" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "base = alt.Chart(df)\n", + "bar = base.mark_bar().encode(\n", + " x=alt.X(field='temperature', \n", + " type='quantitative', \n", + " aggregate='count', \n", + " stack='normalize',\n", + " scale=alt.Scale(type='linear', zero=True)),\n", + " y=alt.Y(field='temperature', \n", + " type='quantitative',\n", + " bin=alt.Bin(maxbins=10),\n", + " scale=alt.Scale(type='linear')),\n", + " color=alt.Color(field='condition', type='nominal')\n", + ")\n", + "display_chart(bar)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Multi Mark (Layered) Charts" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Bar with a Tick" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'field': [{'name': 'temperature', 'type': 'number'}],\n", + " 'number_rows': 100,\n", + " 'view': [{'mark': [{'encoding': [{'aggregate': 'mean',\n", + " 'channel': 'x',\n", + " 'field': 'temperature'}],\n", + " 'type': 'bar'},\n", + " {'encoding': [{'channel': 'x', 'field': 'temperature'}],\n", + " 'type': 'tick'}],\n", + " 'scale': [{'channel': 'x', 'type': 'linear', 'zero': 'true'}]}]}\n" + ] + } + ], + "source": [ + "facts = ['attribute(number_rows,root,100).',\n", + " 'entity(field,root,temperature).',\n", + " 'attribute((field,name),temperature,temperature).',\n", + " 'attribute((field,type),temperature,number).',\n", + " 'entity(view,root,0).',\n", + " 'entity(mark,0,1).',\n", + " 'attribute((mark,type),1,bar).',\n", + " 'entity(encoding,1,2).',\n", + " 'attribute((encoding,channel),2,x).',\n", + " 'attribute((encoding,aggregate),2,mean).',\n", + " 'attribute((encoding,field),2,temperature).',\n", + " 'entity(mark,0,3).',\n", + " 'attribute((mark,type),3,tick).',\n", + " 'entity(encoding,3,4).',\n", + " 'attribute((encoding,channel),4,x).',\n", + " 'attribute((encoding,field),4,temperature).',\n", + " 'entity(scale,0,5).',\n", + " 'attribute((scale,channel),5,x).',\n", + " 'attribute((scale,type),5,linear).',\n", + " 'attribute((scale,zero),5,true).']\n", + "spec = facts_to_dict(facts)\n", + "pprint(spec)" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", + " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", + " 'layer': [{'encoding': {'x': {'aggregate': 'mean',\n", + " 'field': 'temperature',\n", + " 'scale': {'type': 'linear', 'zero': True},\n", + " 'type': 'quantitative'}},\n", + " 'mark': 'bar'},\n", + " {'encoding': {'x': {'field': 'temperature',\n", + " 'scale': {'type': 'linear', 'zero': True},\n", + " 'type': 'quantitative'}},\n", + " 'mark': 'tick'}]}\n" + ] + }, + { + "data": { + "text/html": "\n
\n", + "text/plain": "alt.LayerChart(...)" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "base = alt.Chart(df)\n", + "bar = base.mark_bar().encode(\n", + " x=alt.X(field='temperature', \n", + " type='quantitative',\n", + " aggregate='mean',\n", + " scale=alt.Scale(type='linear', zero=True)),\n", + ")\n", + "tick = base.mark_tick().encode(\n", + " x=alt.X(field='temperature', \n", + " type='quantitative',\n", + " scale=alt.Scale(type='linear', zero=True)),\n", + ")\n", + "display_chart(bar + tick)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Facets" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Facet Scatterplot into Columns" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'field': [{'name': 'temperature', 'type': 'number'},\n", + " {'name': 'wind', 'type': 'number'},\n", + " {'name': 'condition', 'type': 'string'}],\n", + " 'number_rows': 100,\n", + " 'view': [{'facet': [{'channel': 'col', 'field': 'condition'}],\n", + " 'mark': [{'encoding': [{'channel': 'x', 'field': 'temperature'},\n", + " {'channel': 'y', 'field': 'wind'}],\n", + " 'type': 'point'}],\n", + " 'scale': [{'channel': 'x', 'type': 'linear'},\n", + " {'channel': 'y', 'type': 'linear'}]}]}\n" + ] + } + ], + "source": [ + "facts = ['attribute(number_rows,root,100).',\n", + " 'entity(field,root,temperature).',\n", + " 'attribute((field,name),temperature,temperature).',\n", + " 'attribute((field,type),temperature,number).',\n", + " 'entity(field,root,wind).',\n", + " 'attribute((field,name),wind,wind).',\n", + " 'attribute((field,type),wind,number).',\n", + " 'entity(field,root,condition).',\n", + " 'attribute((field,name),condition,condition).',\n", + " 'attribute((field,type),condition,string).',\n", + " 'entity(view,root,0).',\n", + " 'entity(mark,0,1).',\n", + " 'attribute((mark,type),1,point).',\n", + " 'entity(encoding,1,2).',\n", + " 'attribute((encoding,channel),2,x).',\n", + " 'attribute((encoding,field),2,temperature).',\n", + " 'entity(encoding,1,3).',\n", + " 'attribute((encoding,channel),3,y).',\n", + " 'attribute((encoding,field),3,wind).',\n", + " 'entity(scale,0,4).',\n", + " 'attribute((scale,channel),4,x).',\n", + " 'attribute((scale,type),4,linear).',\n", + " 'entity(scale,0,5).',\n", + " 'attribute((scale,channel),5,y).',\n", + " 'attribute((scale,type),5,linear).',\n", + " 'entity(facet,0,6).',\n", + " 'attribute((facet,channel),6,col).',\n", + " 'attribute((facet,field),6,condition).']\n", + "spec = facts_to_dict(facts)\n", + "pprint(spec)" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", + " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", + " 'facet': {'column': {'field': 'condition', 'type': 'nominal'}},\n", + " 'spec': {'encoding': {'x': {'field': 'temperature', 'type': 'quantitative'},\n", + " 'y': {'field': 'wind', 'type': 'quantitative'}},\n", + " 'mark': 'point'}}\n" + ] + }, + { + "data": { + "text/html": "\n
\n", + "text/plain": "alt.FacetChart(...)" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "base = alt.Chart(df)\n", + "point = base.mark_point().encode(\n", + " x=alt.X(field='temperature', type='quantitative'),\n", + " y=alt.Y(field='wind', type='quantitative')\n", + ")\n", + "facet = point.facet(\n", + " column=alt.Column(field='condition', type='nominal')\n", + ")\n", + "display_chart(facet)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Facet Scatterplot by Binned Data into Columns" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'field': [{'name': 'temperature', 'type': 'number'},\n", + " {'name': 'wind', 'type': 'number'},\n", + " {'name': 'condition', 'type': 'string'}],\n", + " 'number_rows': 100,\n", + " 'view': [{'facet': [{'binning': 10, 'channel': 'col', 'field': 'temperature'}],\n", + " 'mark': [{'encoding': [{'channel': 'x', 'field': 'condition'},\n", + " {'channel': 'y', 'field': 'wind'}],\n", + " 'type': 'point'}],\n", + " 'scale': [{'channel': 'x', 'type': 'ordinal'},\n", + " {'channel': 'y', 'type': 'linear'}]}]}\n" + ] + } + ], + "source": [ + "facts = ['attribute(number_rows,root,100).',\n", + " 'entity(field,root,temperature).',\n", + " 'attribute((field,name),temperature,temperature).',\n", + " 'attribute((field,type),temperature,number).',\n", + " 'entity(field,root,wind).',\n", + " 'attribute((field,name),wind,wind).',\n", + " 'attribute((field,type),wind,number).',\n", + " 'entity(field,root,condition).',\n", + " 'attribute((field,name),condition,condition).',\n", + " 'attribute((field,type),condition,string).',\n", + " 'entity(view,root,0).',\n", + " 'entity(mark,0,1).',\n", + " 'attribute((mark,type),1,point).',\n", + " 'entity(encoding,1,2).',\n", + " 'attribute((encoding,channel),2,x).',\n", + " 'attribute((encoding,field),2,condition).',\n", + " 'entity(encoding,1,3).',\n", + " 'attribute((encoding,channel),3,y).',\n", + " 'attribute((encoding,field),3,wind).',\n", + " 'entity(scale,0,4).',\n", + " 'attribute((scale,channel),4,x).',\n", + " 'attribute((scale,type),4,ordinal).',\n", + " 'entity(scale,0,5).',\n", + " 'attribute((scale,channel),5,y).',\n", + " 'attribute((scale,type),5,linear).',\n", + " 'entity(facet,0,6).',\n", + " 'attribute((facet,channel),6,col).',\n", + " 'attribute((facet,field),6,temperature).',\n", + " 'attribute((facet,binning),6,10).']\n", + "spec = facts_to_dict(facts)\n", + "pprint(spec)" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", + " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", + " 'facet': {'column': {'bin': {'maxbins': 10},\n", + " 'field': 'temperature',\n", + " 'type': 'quantitative'}},\n", + " 'spec': {'encoding': {'x': {'field': 'condition',\n", + " 'scale': {'type': 'ordinal'},\n", + " 'type': 'nominal'},\n", + " 'y': {'field': 'wind',\n", + " 'scale': {'type': 'linear'},\n", + " 'type': 'quantitative'}},\n", + " 'mark': 'point'}}\n" + ] + }, + { + "data": { + "text/html": "\n
\n", + "text/plain": "alt.FacetChart(...)" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "base = alt.Chart(df)\n", + "point = base.mark_point().encode(\n", + " x=alt.X(field='condition', type='nominal', scale=alt.Scale(type='ordinal')),\n", + " y=alt.Y(field='wind', type='quantitative', scale=alt.Scale(type='linear'))\n", + ")\n", + "facet = point.facet(\n", + " column=alt.Column(field='temperature', type='quantitative', bin=alt.Bin(maxbins=10))\n", + ")\n", + "display_chart(facet)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Multiple Views" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Tick Plot and Histogram" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'field': [{'name': 'temperature', 'type': 'number'},\n", + " {'name': 'condition', 'type': 'string'}],\n", + " 'number_rows': 100,\n", + " 'view': [{'mark': [{'encoding': [{'channel': 'y', 'field': 'temperature'}],\n", + " 'type': 'tick'}],\n", + " 'scale': [{'channel': 'y', 'type': 'linear', 'zero': 'true'}]},\n", + " {'mark': [{'encoding': [{'channel': 'x', 'field': 'condition'},\n", + " {'aggregate': 'count', 'channel': 'y'}],\n", + " 'type': 'bar'}],\n", + " 'scale': [{'channel': 'x', 'type': 'ordinal'},\n", + " {'channel': 'y', 'type': 'linear', 'zero': 'true'}]}]}\n" + ] + } + ], + "source": [ + "facts = ['attribute(number_rows,root,100).',\n", + " 'entity(field,root,temperature).',\n", + " 'attribute((field,name),temperature,temperature).',\n", + " 'attribute((field,type),temperature,number).',\n", + " 'entity(field,root,condition).',\n", + " 'attribute((field,name),condition,condition).',\n", + " 'attribute((field,type),condition,string).',\n", + " 'entity(view,root,0).',\n", + " 'entity(mark,0,1).',\n", + " 'attribute((mark,type),1,tick).',\n", + " 'entity(encoding,1,2).',\n", + " 'attribute((encoding,channel),2,y).',\n", + " 'attribute((encoding,field),2,temperature).',\n", + " 'entity(scale,0,3).',\n", + " 'attribute((scale,channel),3,y).',\n", + " 'attribute((scale,type),3,linear).',\n", + " 'attribute((scale,zero),3,true).',\n", + " 'entity(view,root,4).',\n", + " 'entity(mark,4,5).',\n", + " 'attribute((mark,type),5,bar).',\n", + " 'entity(encoding,5,6).',\n", + " 'attribute((encoding,channel),6,x).',\n", + " 'attribute((encoding,field),6,condition).',\n", + " 'entity(encoding,5,7).',\n", + " 'attribute((encoding,channel),7,y).',\n", + " 'attribute((encoding,aggregate),7,count).',\n", + " 'entity(scale,4,8).',\n", + " 'attribute((scale,channel),8,x).',\n", + " 'attribute((scale,type),8,ordinal).',\n", + " 'entity(scale,4,9).',\n", + " 'attribute((scale,channel),9,y).',\n", + " 'attribute((scale,type),9,linear).',\n", + " 'attribute((scale,zero),9,true).']\n", + "spec = facts_to_dict(facts)\n", + "pprint(spec)" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", + " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", + " 'hconcat': [{'encoding': {'y': {'field': 'temperature',\n", + " 'scale': {'type': 'linear', 'zero': True},\n", + " 'type': 'quantitative'}},\n", + " 'mark': 'tick'},\n", + " {'encoding': {'x': {'field': 'condition',\n", + " 'scale': {'type': 'ordinal'},\n", + " 'type': 'nominal'},\n", + " 'y': {'aggregate': 'count',\n", + " 'field': 'condition',\n", + " 'type': 'nominal'}},\n", + " 'mark': 'bar'}]}\n" + ] + }, + { + "data": { + "text/html": "\n
\n", + "text/plain": "alt.HConcatChart(...)" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "base = alt.Chart(df)\n", + "\n", + "tick = base.mark_tick().encode(\n", + " y=alt.Y(field='temperature', type='quantitative', scale=alt.Scale(type='linear', zero=True))\n", + ")\n", + "view_1 = tick\n", + "\n", + "bar = base.mark_bar().encode(\n", + " x=alt.X(field='condition', type='nominal', scale=alt.Scale(type='ordinal')),\n", + " y=alt.Y(field='condition', type='nominal', aggregate='count')\n", + ")\n", + "view_2 = bar\n", + "\n", + "display_chart(view_1 | view_2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Tick Plot and Histogram with Shared Y-Scale" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'field': [{'name': 'temperature', 'type': 'number'},\n", + " {'name': 'condition', 'type': 'string'}],\n", + " 'number_rows': 100,\n", + " 'scale': [{'channel': 'y', 'type': 'linear', 'zero': 'true'}],\n", + " 'view': [{'mark': [{'encoding': [{'channel': 'y', 'field': 'temperature'}],\n", + " 'type': 'tick'}]},\n", + " {'mark': [{'encoding': [{'aggregate': 'mean',\n", + " 'channel': 'y',\n", + " 'field': 'temperature'},\n", + " {'channel': 'x', 'field': 'condition'}],\n", + " 'type': 'bar'}],\n", + " 'scale': [{'channel': 'x', 'type': 'ordinal'}]}]}\n" + ] + } + ], + "source": [ + "facts = ['attribute(number_rows,root,100).',\n", + " 'entity(field,root,temperature).',\n", + " 'attribute((field,name),temperature,temperature).',\n", + " 'attribute((field,type),temperature,number).',\n", + " 'entity(field,root,condition).',\n", + " 'attribute((field,name),condition,condition).',\n", + " 'attribute((field,type),condition,string).',\n", + " 'entity(view,root,0).',\n", + " 'entity(mark,0,1).',\n", + " 'attribute((mark,type),1,tick).',\n", + " 'entity(encoding,1,2).',\n", + " 'attribute((encoding,channel),2,y).',\n", + " 'attribute((encoding,field),2,temperature).',\n", + " 'entity(view,root,3).',\n", + " 'entity(mark,3,4).',\n", + " 'attribute((mark,type),4,bar).',\n", + " 'entity(encoding,4,5).',\n", + " 'attribute((encoding,channel),5,y).',\n", + " 'attribute((encoding,field),5,temperature).',\n", + " 'attribute((encoding,aggregate),5,mean).',\n", + " 'entity(encoding,4,6).',\n", + " 'attribute((encoding,channel),6,x).',\n", + " 'attribute((encoding,field),6,condition).',\n", + " 'entity(scale,3,7).',\n", + " 'attribute((scale,channel),7,x).',\n", + " 'attribute((scale,type),7,ordinal).',\n", + " 'entity(scale,root,8).',\n", + " 'attribute((scale,channel),8,y).',\n", + " 'attribute((scale,type),8,linear).',\n", + " 'attribute((scale,zero),8,true).']\n", + "spec = facts_to_dict(facts)\n", + "pprint(spec)" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", + " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", + " 'hconcat': [{'encoding': {'y': {'field': 'temperature',\n", + " 'type': 'quantitative'}},\n", + " 'mark': 'tick'},\n", + " {'encoding': {'x': {'field': 'condition', 'type': 'nominal'},\n", + " 'y': {'aggregate': 'mean',\n", + " 'field': 'temperature',\n", + " 'type': 'quantitative'}},\n", + " 'mark': 'bar'}],\n", + " 'resolve': {'scale': {'y': 'shared'}}}\n" + ] + }, + { + "data": { + "text/html": "\n
\n", + "text/plain": "alt.HConcatChart(...)" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "base = alt.Chart(df)\n", + "\n", + "tick = base.mark_tick().encode(\n", + " y=alt.Y(field='temperature', type='quantitative')\n", + ")\n", + "view_1 = tick\n", + "\n", + "bar = base.mark_bar().encode(\n", + " x=alt.X(field='condition', type='nominal'),\n", + " y=alt.Y(field='temperature', type='quantitative', aggregate='mean')\n", + ")\n", + "view_2 = bar\n", + "chart = alt.hconcat(view_1, view_2).resolve_scale(\n", + " y='shared'\n", + ")\n", + "\n", + "display_chart(chart)" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.3" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} From 932ed30f8e2825399fccc26f8809341641fed075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Tue, 8 Nov 2022 08:58:56 +0100 Subject: [PATCH 02/45] feat: base renderer progress --- docs/facts/examples-vl.ipynb | 1359 +++++++++++++++++++--------------- draco/renderer.py | 155 ++++ draco/utils.py | 6 + 3 files changed, 916 insertions(+), 604 deletions(-) create mode 100644 draco/renderer.py diff --git a/docs/facts/examples-vl.ipynb b/docs/facts/examples-vl.ipynb index 25235fd0..026d3970 100644 --- a/docs/facts/examples-vl.ipynb +++ b/docs/facts/examples-vl.ipynb @@ -11,7 +11,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 164, "metadata": {}, "outputs": [], "source": [ @@ -24,7 +24,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 165, "metadata": {}, "outputs": [], "source": [ @@ -35,24 +35,25 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 166, "metadata": {}, "outputs": [], "source": [ "from IPython.display import display\n", "import json\n", "\n", + "\n", "def display_chart(chart: alt.Chart):\n", " dct = json.loads(chart.to_json())\n", - " dct.pop('data')\n", - " dct.pop('datasets')\n", + " dct.pop(\"data\")\n", + " dct.pop(\"datasets\")\n", " pprint(dct)\n", " display(chart)" ] }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 167, "metadata": {}, "outputs": [], "source": [ @@ -70,22 +71,25 @@ " \"temperature\": [random.uniform(-10, 44) for _ in range(NUM_ROWS)],\n", " \"wind\": [random.uniform(0, 100) for _ in range(NUM_ROWS)],\n", " \"precipitation\": [random.uniform(0, 100) for _ in range(NUM_ROWS)],\n", - " \"condition\": [random.choice([\"drizzle\", \"fog\", \"rain\", \"sun\", \"snow\"]) for _ in range(NUM_ROWS)],\n", + " \"condition\": [\n", + " random.choice([\"drizzle\", \"fog\", \"rain\", \"sun\", \"snow\"])\n", + " for _ in range(NUM_ROWS)\n", + " ],\n", " }\n", - ")\n" + ")" ] }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 168, "metadata": {}, "outputs": [ { "data": { - "text/plain": " temperature wind precipitation condition\n0 39.357872 11.562264 88.420514 fog\n1 -5.947155 86.907017 70.558329 rain\n2 32.827656 97.658974 82.655115 sun\n3 17.525999 65.527975 53.862565 snow\n4 -6.808827 37.034294 93.865255 drizzle", - "text/html": "
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
temperaturewindprecipitationcondition
039.35787211.56226488.420514fog
1-5.94715586.90701770.558329rain
232.82765697.65897482.655115sun
317.52599965.52797553.862565snow
4-6.80882737.03429493.865255drizzle
\n
" + "text/plain": " temperature wind precipitation condition\n0 15.949649 44.064475 39.571021 sun\n1 35.804103 57.347114 51.104157 snow\n2 34.390488 96.360482 40.969804 drizzle\n3 7.204886 25.146399 85.490179 drizzle\n4 19.552840 57.883961 73.697679 sun", + "text/html": "
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
temperaturewindprecipitationcondition
015.94964944.06447539.571021sun
135.80410357.34711451.104157snow
234.39048896.36048240.969804drizzle
37.20488625.14639985.490179drizzle
419.55284057.88396173.697679sun
\n
" }, - "execution_count": 44, + "execution_count": 168, "metadata": {}, "output_type": "execute_result" } @@ -110,7 +114,7 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 169, "metadata": {}, "outputs": [ { @@ -126,26 +130,28 @@ } ], "source": [ - "facts = ['attribute(number_rows,root,100).',\n", - " 'entity(field,root,temperature).',\n", - " 'attribute((field,name),temperature,temperature).',\n", - " 'attribute((field,type),temperature,number).',\n", - " 'entity(view,root,0).',\n", - " 'entity(mark,0,1).',\n", - " 'attribute((mark,type),1,tick).',\n", - " 'entity(encoding,1,2).',\n", - " 'attribute((encoding,channel),2,x).',\n", - " 'attribute((encoding,field),2,temperature).',\n", - " 'entity(scale,0,3).',\n", - " 'attribute((scale,channel),3,x).',\n", - " 'attribute((scale,type),3,linear).']\n", + "facts = [\n", + " \"attribute(number_rows,root,100).\",\n", + " \"entity(field,root,temperature).\",\n", + " \"attribute((field,name),temperature,temperature).\",\n", + " \"attribute((field,type),temperature,number).\",\n", + " \"entity(view,root,0).\",\n", + " \"entity(mark,0,1).\",\n", + " \"attribute((mark,type),1,tick).\",\n", + " \"entity(encoding,1,2).\",\n", + " \"attribute((encoding,channel),2,x).\",\n", + " \"attribute((encoding,field),2,temperature).\",\n", + " \"entity(scale,0,3).\",\n", + " \"attribute((scale,channel),3,x).\",\n", + " \"attribute((scale,type),3,linear).\",\n", + "]\n", "spec = facts_to_dict(facts)\n", "pprint(spec)" ] }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 170, "metadata": {}, "outputs": [ { @@ -170,7 +176,7 @@ }, { "data": { - "text/html": "\n
\n", + "text/html": "\n
\n", "text/plain": "alt.Chart(...)" }, "metadata": {}, @@ -180,7 +186,7 @@ "source": [ "base = alt.Chart(df)\n", "tick = base.mark_tick().encode(\n", - " x=alt.X(field='temperature', type='quantitative', scale=alt.Scale(type='linear'))\n", + " x=alt.X(field=\"temperature\", type=\"quantitative\", scale=alt.Scale(type=\"linear\"))\n", ")\n", "display_chart(tick)" ] @@ -194,7 +200,7 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 171, "metadata": {}, "outputs": [ { @@ -210,26 +216,28 @@ } ], "source": [ - "facts = ['attribute(number_rows,root,100).',\n", - " 'entity(field,root,temperature).',\n", - " 'attribute((field,name),temperature,temperature).',\n", - " 'attribute((field,type),temperature,number).',\n", - " 'entity(view,root,0).',\n", - " 'entity(mark,0,1).',\n", - " 'attribute((mark,type),1,tick).',\n", - " 'entity(encoding,1,2).',\n", - " 'attribute((encoding,channel),2,x).',\n", - " 'attribute((encoding,field),2,temperature).',\n", - " 'entity(scale,0,3).',\n", - " 'attribute((scale,channel),3,x).',\n", - " 'attribute((scale,type),3,log).']\n", + "facts = [\n", + " \"attribute(number_rows,root,100).\",\n", + " \"entity(field,root,temperature).\",\n", + " \"attribute((field,name),temperature,temperature).\",\n", + " \"attribute((field,type),temperature,number).\",\n", + " \"entity(view,root,0).\",\n", + " \"entity(mark,0,1).\",\n", + " \"attribute((mark,type),1,tick).\",\n", + " \"entity(encoding,1,2).\",\n", + " \"attribute((encoding,channel),2,x).\",\n", + " \"attribute((encoding,field),2,temperature).\",\n", + " \"entity(scale,0,3).\",\n", + " \"attribute((scale,channel),3,x).\",\n", + " \"attribute((scale,type),3,log).\",\n", + "]\n", "spec = facts_to_dict(facts)\n", "pprint(spec)" ] }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 172, "metadata": {}, "outputs": [ { @@ -247,7 +255,7 @@ }, { "data": { - "text/html": "\n
\n", + "text/html": "\n
\n", "text/plain": "alt.Chart(...)" }, "metadata": {}, @@ -255,11 +263,9 @@ } ], "source": [ - "base = alt.Chart(df).transform_filter(\n", - " datum.temperature > 0\n", - ")\n", + "base = alt.Chart(df).transform_filter(datum.temperature > 0)\n", "tick = base.mark_tick().encode(\n", - " x=alt.X(field='temperature', type='quantitative', scale=alt.Scale(type='log'))\n", + " x=alt.X(field=\"temperature\", type=\"quantitative\", scale=alt.Scale(type=\"log\"))\n", ")\n", "display_chart(tick)" ] @@ -273,7 +279,7 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 173, "metadata": {}, "outputs": [ { @@ -295,38 +301,40 @@ } ], "source": [ - "facts = ['attribute(number_rows,root,100).',\n", - " 'entity(field,root,temperature).',\n", - " 'attribute((field,name),temperature,temperature).',\n", - " 'attribute((field,type),temperature,number).',\n", - " 'entity(field,root,condition).',\n", - " 'attribute((field,name),condition,condition).',\n", - " 'attribute((field,type),condition,string).',\n", - " 'entity(view,root,0).',\n", - " 'attribute((view,coordinates),0,cartesian).',\n", - " 'entity(mark,0,1).',\n", - " 'attribute((mark,type),1,bar).',\n", - " 'entity(encoding,1,2).',\n", - " 'attribute((encoding,channel),2,x).',\n", - " 'attribute((encoding,field),2,condition).',\n", - " 'entity(encoding,1,3).',\n", - " 'attribute((encoding,channel),3,y).',\n", - " 'attribute((encoding,field),3,temperature).',\n", - " 'attribute((encoding,aggregate),3,mean).',\n", - " 'entity(scale,0,4).',\n", - " 'attribute((scale,channel),4,x).',\n", - " 'attribute((scale,type),4,ordinal).',\n", - " 'entity(scale,0,5).',\n", - " 'attribute((scale,channel),5,y).',\n", - " 'attribute((scale,type),5,linear).',\n", - " 'attribute((scale,zero),5,true).']\n", + "facts = [\n", + " \"attribute(number_rows,root,100).\",\n", + " \"entity(field,root,temperature).\",\n", + " \"attribute((field,name),temperature,temperature).\",\n", + " \"attribute((field,type),temperature,number).\",\n", + " \"entity(field,root,condition).\",\n", + " \"attribute((field,name),condition,condition).\",\n", + " \"attribute((field,type),condition,string).\",\n", + " \"entity(view,root,0).\",\n", + " \"attribute((view,coordinates),0,cartesian).\",\n", + " \"entity(mark,0,1).\",\n", + " \"attribute((mark,type),1,bar).\",\n", + " \"entity(encoding,1,2).\",\n", + " \"attribute((encoding,channel),2,x).\",\n", + " \"attribute((encoding,field),2,condition).\",\n", + " \"entity(encoding,1,3).\",\n", + " \"attribute((encoding,channel),3,y).\",\n", + " \"attribute((encoding,field),3,temperature).\",\n", + " \"attribute((encoding,aggregate),3,mean).\",\n", + " \"entity(scale,0,4).\",\n", + " \"attribute((scale,channel),4,x).\",\n", + " \"attribute((scale,type),4,ordinal).\",\n", + " \"entity(scale,0,5).\",\n", + " \"attribute((scale,channel),5,y).\",\n", + " \"attribute((scale,type),5,linear).\",\n", + " \"attribute((scale,zero),5,true).\",\n", + "]\n", "spec = facts_to_dict(facts)\n", "pprint(spec)" ] }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 174, "metadata": {}, "outputs": [ { @@ -347,7 +355,7 @@ }, { "data": { - "text/html": "\n
\n", + "text/html": "\n
\n", "text/plain": "alt.Chart(...)" }, "metadata": {}, @@ -357,13 +365,13 @@ "source": [ "base = alt.Chart(df)\n", "bar = base.mark_bar().encode(\n", - " x=alt.X(field='condition', \n", - " type='nominal', \n", - " scale=alt.Scale(type='ordinal')),\n", - " y=alt.Y(field='temperature', \n", - " type='quantitative', \n", - " aggregate='mean', \n", - " scale=alt.Scale(type='linear', zero=True))\n", + " x=alt.X(field=\"condition\", type=\"nominal\", scale=alt.Scale(type=\"ordinal\")),\n", + " y=alt.Y(\n", + " field=\"temperature\",\n", + " type=\"quantitative\",\n", + " aggregate=\"mean\",\n", + " scale=alt.Scale(type=\"linear\", zero=True),\n", + " ),\n", ")\n", "display_chart(bar)" ] @@ -377,7 +385,7 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 175, "metadata": {}, "outputs": [ { @@ -399,38 +407,40 @@ } ], "source": [ - "facts = ['attribute(number_rows,root,100).',\n", - " 'entity(field,root,temperature).',\n", - " 'attribute((field,name),temperature,temperature).',\n", - " 'attribute((field,type),temperature,number).',\n", - " 'entity(field,root,condition).',\n", - " 'attribute((field,name),condition,condition).',\n", - " 'attribute((field,type),condition,string).',\n", - " 'entity(view,root,0).',\n", - " 'attribute((view,coordinates),0,polar).',\n", - " 'entity(mark,0,1).',\n", - " 'attribute((mark,type),1,bar).',\n", - " 'entity(encoding,1,2).',\n", - " 'attribute((encoding,channel),2,x).',\n", - " 'attribute((encoding,field),2,condition).',\n", - " 'entity(encoding,1,3).',\n", - " 'attribute((encoding,channel),3,y).',\n", - " 'attribute((encoding,field),3,temperature).',\n", - " 'attribute((encoding,aggregate),3,mean).',\n", - " 'entity(scale,0,4).',\n", - " 'attribute((scale,channel),4,x).',\n", - " 'attribute((scale,type),4,ordinal).',\n", - " 'entity(scale,0,5).',\n", - " 'attribute((scale,channel),5,y).',\n", - " 'attribute((scale,type),5,linear).',\n", - " 'attribute((scale,zero),5,true).']\n", + "facts = [\n", + " \"attribute(number_rows,root,100).\",\n", + " \"entity(field,root,temperature).\",\n", + " \"attribute((field,name),temperature,temperature).\",\n", + " \"attribute((field,type),temperature,number).\",\n", + " \"entity(field,root,condition).\",\n", + " \"attribute((field,name),condition,condition).\",\n", + " \"attribute((field,type),condition,string).\",\n", + " \"entity(view,root,0).\",\n", + " \"attribute((view,coordinates),0,polar).\",\n", + " \"entity(mark,0,1).\",\n", + " \"attribute((mark,type),1,bar).\",\n", + " \"entity(encoding,1,2).\",\n", + " \"attribute((encoding,channel),2,x).\",\n", + " \"attribute((encoding,field),2,condition).\",\n", + " \"entity(encoding,1,3).\",\n", + " \"attribute((encoding,channel),3,y).\",\n", + " \"attribute((encoding,field),3,temperature).\",\n", + " \"attribute((encoding,aggregate),3,mean).\",\n", + " \"entity(scale,0,4).\",\n", + " \"attribute((scale,channel),4,x).\",\n", + " \"attribute((scale,type),4,ordinal).\",\n", + " \"entity(scale,0,5).\",\n", + " \"attribute((scale,channel),5,y).\",\n", + " \"attribute((scale,type),5,linear).\",\n", + " \"attribute((scale,zero),5,true).\",\n", + "]\n", "spec = facts_to_dict(facts)\n", "pprint(spec)" ] }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 176, "metadata": {}, "outputs": [ { @@ -454,7 +464,7 @@ }, { "data": { - "text/html": "\n
\n", + "text/html": "\n
\n", "text/plain": "alt.LayerChart(...)" }, "metadata": {}, @@ -463,14 +473,14 @@ ], "source": [ "base = alt.Chart(df)\n", - "arc = base.mark_arc(stroke='#ffffff').encode(\n", - " theta=alt.Theta(field='condition', type='nominal'),\n", - " radius=alt.Radius(field='temperature', type='quantitative', aggregate='mean')\n", + "arc = base.mark_arc(stroke=\"#ffffff\").encode(\n", + " theta=alt.Theta(field=\"condition\", type=\"nominal\"),\n", + " radius=alt.Radius(field=\"temperature\", type=\"quantitative\", aggregate=\"mean\"),\n", ")\n", "text = base.mark_text(radiusOffset=15).encode(\n", - " theta=alt.Theta(field='condition', type='nominal'),\n", - " radius=alt.Radius(field='temperature', type='quantitative', aggregate='mean'),\n", - " text=alt.Text(field='condition', type='nominal')\n", + " theta=alt.Theta(field=\"condition\", type=\"nominal\"),\n", + " radius=alt.Radius(field=\"temperature\", type=\"quantitative\", aggregate=\"mean\"),\n", + " text=alt.Text(field=\"condition\", type=\"nominal\"),\n", ")\n", "display_chart(arc + text)" ] @@ -484,7 +494,7 @@ }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 177, "metadata": {}, "outputs": [ { @@ -502,33 +512,35 @@ } ], "source": [ - "facts = ['attribute(number_rows,root,100).',\n", - " 'entity(field,root,condition).',\n", - " 'attribute((field,name),condition,condition).',\n", - " 'attribute((field,type),condition,string).',\n", - " 'entity(view,root,0).',\n", - " 'entity(mark,0,1).',\n", - " 'attribute((mark,type),1,bar).',\n", - " 'entity(encoding,1,2).',\n", - " 'attribute((encoding,channel),2,x).',\n", - " 'attribute((encoding,field),2,condition).',\n", - " 'entity(encoding,1,3).',\n", - " 'attribute((encoding,channel),3,y).',\n", - " 'attribute((encoding,aggregate),3,count).',\n", - " 'entity(scale,0,4).',\n", - " 'attribute((scale,channel),4,x).',\n", - " 'attribute((scale,type),4,ordinal).',\n", - " 'entity(scale,0,5).',\n", - " 'attribute((scale,channel),5,y).',\n", - " 'attribute((scale,type),5,linear).',\n", - " 'attribute((scale,zero),5,true).']\n", + "facts = [\n", + " \"attribute(number_rows,root,100).\",\n", + " \"entity(field,root,condition).\",\n", + " \"attribute((field,name),condition,condition).\",\n", + " \"attribute((field,type),condition,string).\",\n", + " \"entity(view,root,0).\",\n", + " \"entity(mark,0,1).\",\n", + " \"attribute((mark,type),1,bar).\",\n", + " \"entity(encoding,1,2).\",\n", + " \"attribute((encoding,channel),2,x).\",\n", + " \"attribute((encoding,field),2,condition).\",\n", + " \"entity(encoding,1,3).\",\n", + " \"attribute((encoding,channel),3,y).\",\n", + " \"attribute((encoding,aggregate),3,count).\",\n", + " \"entity(scale,0,4).\",\n", + " \"attribute((scale,channel),4,x).\",\n", + " \"attribute((scale,type),4,ordinal).\",\n", + " \"entity(scale,0,5).\",\n", + " \"attribute((scale,channel),5,y).\",\n", + " \"attribute((scale,type),5,linear).\",\n", + " \"attribute((scale,zero),5,true).\",\n", + "]\n", "spec = facts_to_dict(facts)\n", "pprint(spec)" ] }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 178, "metadata": {}, "outputs": [ { @@ -549,7 +561,7 @@ }, { "data": { - "text/html": "\n
\n", + "text/html": "\n
\n", "text/plain": "alt.Chart(...)" }, "metadata": {}, @@ -559,13 +571,13 @@ "source": [ "base = alt.Chart(df)\n", "bar = base.mark_bar().encode(\n", - " x=alt.X(field='condition', \n", - " type='nominal', \n", - " scale=alt.Scale(type='ordinal')),\n", - " y=alt.Y(field='condition', \n", - " type='nominal', \n", - " aggregate='count', \n", - " scale=alt.Scale(type='linear', zero=True))\n", + " x=alt.X(field=\"condition\", type=\"nominal\", scale=alt.Scale(type=\"ordinal\")),\n", + " y=alt.Y(\n", + " field=\"condition\",\n", + " type=\"nominal\",\n", + " aggregate=\"count\",\n", + " scale=alt.Scale(type=\"linear\", zero=True),\n", + " ),\n", ")\n", "display_chart(bar)" ] @@ -579,7 +591,7 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 179, "metadata": {}, "outputs": [ { @@ -599,34 +611,36 @@ } ], "source": [ - "facts = ['attribute(number_rows,root,100).',\n", - " 'entity(field,root,temperature).',\n", - " 'attribute((field,name),temperature,temperature).',\n", - " 'attribute((field,type),temperature,number).',\n", - " 'entity(view,root,0).',\n", - " 'entity(mark,0,1).',\n", - " 'attribute((mark,type),1,bar).',\n", - " 'entity(encoding,1,2).',\n", - " 'attribute((encoding,channel),2,x).',\n", - " 'attribute((encoding,field),2,temperature).',\n", - " 'attribute((encoding,binning),2,10).',\n", - " 'entity(encoding,1,3).',\n", - " 'attribute((encoding,channel),3,y).',\n", - " 'attribute((encoding,aggregate),3,count).',\n", - " 'entity(scale,0,4).',\n", - " 'attribute((scale,channel),4,x).',\n", - " 'attribute((scale,type),4,linear).',\n", - " 'entity(scale,0,5).',\n", - " 'attribute((scale,channel),5,y).',\n", - " 'attribute((scale,type),5,linear).',\n", - " 'attribute((scale,zero),5,true).']\n", + "facts = [\n", + " \"attribute(number_rows,root,100).\",\n", + " \"entity(field,root,temperature).\",\n", + " \"attribute((field,name),temperature,temperature).\",\n", + " \"attribute((field,type),temperature,number).\",\n", + " \"entity(view,root,0).\",\n", + " \"entity(mark,0,1).\",\n", + " \"attribute((mark,type),1,bar).\",\n", + " \"entity(encoding,1,2).\",\n", + " \"attribute((encoding,channel),2,x).\",\n", + " \"attribute((encoding,field),2,temperature).\",\n", + " \"attribute((encoding,binning),2,10).\",\n", + " \"entity(encoding,1,3).\",\n", + " \"attribute((encoding,channel),3,y).\",\n", + " \"attribute((encoding,aggregate),3,count).\",\n", + " \"entity(scale,0,4).\",\n", + " \"attribute((scale,channel),4,x).\",\n", + " \"attribute((scale,type),4,linear).\",\n", + " \"entity(scale,0,5).\",\n", + " \"attribute((scale,channel),5,y).\",\n", + " \"attribute((scale,type),5,linear).\",\n", + " \"attribute((scale,zero),5,true).\",\n", + "]\n", "spec = facts_to_dict(facts)\n", "pprint(spec)" ] }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 180, "metadata": {}, "outputs": [ { @@ -648,7 +662,7 @@ }, { "data": { - "text/html": "\n
\n", + "text/html": "\n
\n", "text/plain": "alt.Chart(...)" }, "metadata": {}, @@ -658,14 +672,18 @@ "source": [ "base = alt.Chart(df)\n", "bar = base.mark_bar().encode(\n", - " x=alt.X(field='temperature', \n", - " type='quantitative',\n", - " bin=alt.Bin(maxbins=10),\n", - " scale=alt.Scale(type='linear')),\n", - " y=alt.Y(field='temperature', \n", - " type='quantitative', \n", - " aggregate='count', \n", - " scale=alt.Scale(type='linear', zero=True))\n", + " x=alt.X(\n", + " field=\"temperature\",\n", + " type=\"quantitative\",\n", + " bin=alt.Bin(maxbins=10),\n", + " scale=alt.Scale(type=\"linear\"),\n", + " ),\n", + " y=alt.Y(\n", + " field=\"temperature\",\n", + " type=\"quantitative\",\n", + " aggregate=\"count\",\n", + " scale=alt.Scale(type=\"linear\", zero=True),\n", + " ),\n", ")\n", "display_chart(bar)" ] @@ -679,7 +697,7 @@ }, { "cell_type": "code", - "execution_count": 57, + "execution_count": 181, "metadata": {}, "outputs": [ { @@ -698,35 +716,37 @@ } ], "source": [ - "facts = ['attribute(number_rows,root,100).',\n", - " 'entity(field,root,temperature).',\n", - " 'attribute((field,name),temperature,temperature).',\n", - " 'attribute((field,type),temperature,number).',\n", - " 'entity(field,root,wind).',\n", - " 'attribute((field,name),wind,wind).',\n", - " 'attribute((field,type),wind,number).',\n", - " 'entity(view,root,0).',\n", - " 'entity(mark,0,1).',\n", - " 'attribute((mark,type),1,point).',\n", - " 'entity(encoding,1,2).',\n", - " 'attribute((encoding,channel),2,x).',\n", - " 'attribute((encoding,field),2,temperature).',\n", - " 'entity(encoding,1,3).',\n", - " 'attribute((encoding,channel),3,y).',\n", - " 'attribute((encoding,field),3,wind).',\n", - " 'entity(scale,0,4).',\n", - " 'attribute((scale,channel),4,x).',\n", - " 'attribute((scale,type),4,linear).',\n", - " 'entity(scale,0,5).',\n", - " 'attribute((scale,channel),5,y).',\n", - " 'attribute((scale,type),5,linear).']\n", + "facts = [\n", + " \"attribute(number_rows,root,100).\",\n", + " \"entity(field,root,temperature).\",\n", + " \"attribute((field,name),temperature,temperature).\",\n", + " \"attribute((field,type),temperature,number).\",\n", + " \"entity(field,root,wind).\",\n", + " \"attribute((field,name),wind,wind).\",\n", + " \"attribute((field,type),wind,number).\",\n", + " \"entity(view,root,0).\",\n", + " \"entity(mark,0,1).\",\n", + " \"attribute((mark,type),1,point).\",\n", + " \"entity(encoding,1,2).\",\n", + " \"attribute((encoding,channel),2,x).\",\n", + " \"attribute((encoding,field),2,temperature).\",\n", + " \"entity(encoding,1,3).\",\n", + " \"attribute((encoding,channel),3,y).\",\n", + " \"attribute((encoding,field),3,wind).\",\n", + " \"entity(scale,0,4).\",\n", + " \"attribute((scale,channel),4,x).\",\n", + " \"attribute((scale,type),4,linear).\",\n", + " \"entity(scale,0,5).\",\n", + " \"attribute((scale,channel),5,y).\",\n", + " \"attribute((scale,type),5,linear).\",\n", + "]\n", "spec = facts_to_dict(facts)\n", "pprint(spec)" ] }, { "cell_type": "code", - "execution_count": 58, + "execution_count": 182, "metadata": {}, "outputs": [ { @@ -746,7 +766,7 @@ }, { "data": { - "text/html": "\n
\n", + "text/html": "\n
\n", "text/plain": "alt.Chart(...)" }, "metadata": {}, @@ -756,12 +776,8 @@ "source": [ "base = alt.Chart(df)\n", "point = base.mark_point().encode(\n", - " x=alt.X(field='temperature', \n", - " type='quantitative', \n", - " scale=alt.Scale(type='linear')),\n", - " y=alt.Y(field='wind',\n", - " type='quantitative', \n", - " scale=alt.Scale(type='linear')),\n", + " x=alt.X(field=\"temperature\", type=\"quantitative\", scale=alt.Scale(type=\"linear\")),\n", + " y=alt.Y(field=\"wind\", type=\"quantitative\", scale=alt.Scale(type=\"linear\")),\n", ")\n", "display_chart(point)" ] @@ -775,7 +791,7 @@ }, { "cell_type": "code", - "execution_count": 59, + "execution_count": 183, "metadata": {}, "outputs": [ { @@ -797,44 +813,46 @@ } ], "source": [ - "facts = ['attribute(number_rows,root,100).',\n", - " 'entity(field,root,temperature).',\n", - " 'attribute((field,name),temperature,temperature).',\n", - " 'attribute((field,type),temperature,number).',\n", - " 'entity(field,root,wind).',\n", - " 'attribute((field,name),wind,wind).',\n", - " 'attribute((field,type),wind,number).',\n", - " 'entity(field,root,condition).',\n", - " 'attribute((field,name),condition,condition).',\n", - " 'attribute((field,type),condition,string).',\n", - " 'entity(view,root,0).',\n", - " 'entity(mark,0,1).',\n", - " 'attribute((mark,type),1,point).',\n", - " 'entity(encoding,1,2).',\n", - " 'attribute((encoding,channel),2,x).',\n", - " 'attribute((encoding,field),2,temperature).',\n", - " 'entity(encoding,1,3).',\n", - " 'attribute((encoding,channel),3,y).',\n", - " 'attribute((encoding,field),3,wind).',\n", - " 'entity(encoding,1,4).',\n", - " 'attribute((encoding,channel),4,color).',\n", - " 'attribute((encoding,field),4,condition).',\n", - " 'entity(scale,0,5).',\n", - " 'attribute((scale,channel),5,x).',\n", - " 'attribute((scale,type),5,linear).',\n", - " 'entity(scale,0,6).',\n", - " 'attribute((scale,channel),6,y).',\n", - " 'attribute((scale,type),6,linear).',\n", - " 'entity(scale,0,7).',\n", - " 'attribute((scale,channel),7,color).',\n", - " 'attribute((scale,type),7,categorical).']\n", + "facts = [\n", + " \"attribute(number_rows,root,100).\",\n", + " \"entity(field,root,temperature).\",\n", + " \"attribute((field,name),temperature,temperature).\",\n", + " \"attribute((field,type),temperature,number).\",\n", + " \"entity(field,root,wind).\",\n", + " \"attribute((field,name),wind,wind).\",\n", + " \"attribute((field,type),wind,number).\",\n", + " \"entity(field,root,condition).\",\n", + " \"attribute((field,name),condition,condition).\",\n", + " \"attribute((field,type),condition,string).\",\n", + " \"entity(view,root,0).\",\n", + " \"entity(mark,0,1).\",\n", + " \"attribute((mark,type),1,point).\",\n", + " \"entity(encoding,1,2).\",\n", + " \"attribute((encoding,channel),2,x).\",\n", + " \"attribute((encoding,field),2,temperature).\",\n", + " \"entity(encoding,1,3).\",\n", + " \"attribute((encoding,channel),3,y).\",\n", + " \"attribute((encoding,field),3,wind).\",\n", + " \"entity(encoding,1,4).\",\n", + " \"attribute((encoding,channel),4,color).\",\n", + " \"attribute((encoding,field),4,condition).\",\n", + " \"entity(scale,0,5).\",\n", + " \"attribute((scale,channel),5,x).\",\n", + " \"attribute((scale,type),5,linear).\",\n", + " \"entity(scale,0,6).\",\n", + " \"attribute((scale,channel),6,y).\",\n", + " \"attribute((scale,type),6,linear).\",\n", + " \"entity(scale,0,7).\",\n", + " \"attribute((scale,channel),7,color).\",\n", + " \"attribute((scale,type),7,categorical).\",\n", + "]\n", "spec = facts_to_dict(facts)\n", "pprint(spec)" ] }, { "cell_type": "code", - "execution_count": 60, + "execution_count": 184, "metadata": {}, "outputs": [ { @@ -857,7 +875,7 @@ }, { "data": { - "text/html": "\n
\n", + "text/html": "\n
\n", "text/plain": "alt.Chart(...)" }, "metadata": {}, @@ -867,22 +885,16 @@ "source": [ "base = alt.Chart(df)\n", "point = base.mark_point().encode(\n", - " x=alt.X(field='temperature', \n", - " type='quantitative', \n", - " scale=alt.Scale(type='linear')),\n", - " y=alt.Y(field='wind',\n", - " type='quantitative', \n", - " scale=alt.Scale(type='linear')),\n", - " color=alt.Color(field='condition',\n", - " type='nominal',\n", - " scale=alt.Scale(type='ordinal'))\n", + " x=alt.X(field=\"temperature\", type=\"quantitative\", scale=alt.Scale(type=\"linear\")),\n", + " y=alt.Y(field=\"wind\", type=\"quantitative\", scale=alt.Scale(type=\"linear\")),\n", + " color=alt.Color(field=\"condition\", type=\"nominal\", scale=alt.Scale(type=\"ordinal\")),\n", ")\n", "display_chart(point)" ] }, { "cell_type": "code", - "execution_count": 61, + "execution_count": 185, "metadata": {}, "outputs": [ { @@ -905,37 +917,39 @@ } ], "source": [ - "facts = ['attribute(number_rows,root,100).',\n", - " 'entity(field,root,temperature).',\n", - " 'attribute((field,name),temperature,temperature).',\n", - " 'attribute((field,type),temperature,number).',\n", - " 'entity(field,root,wind).',\n", - " 'attribute((field,name),wind,wind).',\n", - " 'attribute((field,type),wind,number).',\n", - " 'entity(field,root,precipitation).',\n", - " 'attribute((field,name),precipitation,precipitation).',\n", - " 'attribute((field,type),precipitation,number).',\n", - " 'entity(view,root,0).',\n", - " 'entity(mark,0,1).',\n", - " 'attribute((mark,type),1,point).',\n", - " 'entity(encoding,1,2).',\n", - " 'attribute((encoding,channel),2,x).',\n", - " 'attribute((encoding,field),2,temperature).',\n", - " 'entity(encoding,1,3).',\n", - " 'attribute((encoding,channel),3,y).',\n", - " 'attribute((encoding,field),3,wind).',\n", - " 'entity(encoding,1,4).',\n", - " 'attribute((encoding,channel),4,size).',\n", - " 'attribute((encoding,field),4,precipitation).',\n", - " 'entity(scale,0,5).',\n", - " 'attribute((scale,channel),5,x).',\n", - " 'attribute((scale,type),5,linear).',\n", - " 'entity(scale,0,6).',\n", - " 'attribute((scale,channel),6,y).',\n", - " 'attribute((scale,type),6,linear).',\n", - " 'entity(scale,0,7).',\n", - " 'attribute((scale,channel),7,size).',\n", - " 'attribute((scale,type),7,linear).']\n", + "facts = [\n", + " \"attribute(number_rows,root,100).\",\n", + " \"entity(field,root,temperature).\",\n", + " \"attribute((field,name),temperature,temperature).\",\n", + " \"attribute((field,type),temperature,number).\",\n", + " \"entity(field,root,wind).\",\n", + " \"attribute((field,name),wind,wind).\",\n", + " \"attribute((field,type),wind,number).\",\n", + " \"entity(field,root,precipitation).\",\n", + " \"attribute((field,name),precipitation,precipitation).\",\n", + " \"attribute((field,type),precipitation,number).\",\n", + " \"entity(view,root,0).\",\n", + " \"entity(mark,0,1).\",\n", + " \"attribute((mark,type),1,point).\",\n", + " \"entity(encoding,1,2).\",\n", + " \"attribute((encoding,channel),2,x).\",\n", + " \"attribute((encoding,field),2,temperature).\",\n", + " \"entity(encoding,1,3).\",\n", + " \"attribute((encoding,channel),3,y).\",\n", + " \"attribute((encoding,field),3,wind).\",\n", + " \"entity(encoding,1,4).\",\n", + " \"attribute((encoding,channel),4,size).\",\n", + " \"attribute((encoding,field),4,precipitation).\",\n", + " \"entity(scale,0,5).\",\n", + " \"attribute((scale,channel),5,x).\",\n", + " \"attribute((scale,type),5,linear).\",\n", + " \"entity(scale,0,6).\",\n", + " \"attribute((scale,channel),6,y).\",\n", + " \"attribute((scale,type),6,linear).\",\n", + " \"entity(scale,0,7).\",\n", + " \"attribute((scale,channel),7,size).\",\n", + " \"attribute((scale,type),7,linear).\",\n", + "]\n", "spec = facts_to_dict(facts)\n", "pprint(spec)" ] @@ -949,7 +963,7 @@ }, { "cell_type": "code", - "execution_count": 62, + "execution_count": 186, "metadata": {}, "outputs": [ { @@ -972,7 +986,7 @@ }, { "data": { - "text/html": "\n
\n", + "text/html": "\n
\n", "text/plain": "alt.Chart(...)" }, "metadata": {}, @@ -982,15 +996,11 @@ "source": [ "base = alt.Chart(df)\n", "point = base.mark_point().encode(\n", - " x=alt.X(field='temperature', \n", - " type='quantitative', \n", - " scale=alt.Scale(type='linear')),\n", - " y=alt.Y(field='wind',\n", - " type='quantitative', \n", - " scale=alt.Scale(type='linear')),\n", - " size=alt.Size(field='precipitation', \n", - " type='quantitative', \n", - " scale=alt.Scale(type='linear')),\n", + " x=alt.X(field=\"temperature\", type=\"quantitative\", scale=alt.Scale(type=\"linear\")),\n", + " y=alt.Y(field=\"wind\", type=\"quantitative\", scale=alt.Scale(type=\"linear\")),\n", + " size=alt.Size(\n", + " field=\"precipitation\", type=\"quantitative\", scale=alt.Scale(type=\"linear\")\n", + " ),\n", ")\n", "display_chart(point)" ] @@ -1011,7 +1021,7 @@ }, { "cell_type": "code", - "execution_count": 63, + "execution_count": 187, "metadata": {}, "outputs": [ { @@ -1033,38 +1043,40 @@ } ], "source": [ - "facts = ['attribute(number_rows,root,100).',\n", - " 'entity(field,root,temperature).',\n", - " 'attribute((field,name),temperature,temperature).',\n", - " 'attribute((field,type),temperature,number).',\n", - " 'entity(field,root,condition).',\n", - " 'attribute((field,name),condition,condition).',\n", - " 'attribute((field,type),condition,string).',\n", - " 'entity(view,root,0).',\n", - " 'attribute((view,coordinates),0,polar).',\n", - " 'entity(mark,0,1).',\n", - " 'attribute((mark,type),1,bar).',\n", - " 'entity(encoding,1,2).',\n", - " 'attribute((encoding,channel),2,y).',\n", - " 'attribute((encoding,aggregate),2,count).',\n", - " 'attribute((encoding,stack),2,zero).',\n", - " 'entity(encoding,1,3).',\n", - " 'attribute((encoding,channel),3,color).',\n", - " 'attribute((encoding,field),3,condition).',\n", - " 'entity(scale,0,4).',\n", - " 'attribute((scale,channel),4,y).',\n", - " 'attribute((scale,type),4,linear).',\n", - " 'attribute((scale,zero),4,true).',\n", - " 'entity(scale,0,5).',\n", - " 'attribute((scale,channel),5,color).',\n", - " 'attribute((scale,type),5,categorical).']\n", + "facts = [\n", + " \"attribute(number_rows,root,100).\",\n", + " \"entity(field,root,temperature).\",\n", + " \"attribute((field,name),temperature,temperature).\",\n", + " \"attribute((field,type),temperature,number).\",\n", + " \"entity(field,root,condition).\",\n", + " \"attribute((field,name),condition,condition).\",\n", + " \"attribute((field,type),condition,string).\",\n", + " \"entity(view,root,0).\",\n", + " \"attribute((view,coordinates),0,polar).\",\n", + " \"entity(mark,0,1).\",\n", + " \"attribute((mark,type),1,bar).\",\n", + " \"entity(encoding,1,2).\",\n", + " \"attribute((encoding,channel),2,y).\",\n", + " \"attribute((encoding,aggregate),2,count).\",\n", + " \"attribute((encoding,stack),2,zero).\",\n", + " \"entity(encoding,1,3).\",\n", + " \"attribute((encoding,channel),3,color).\",\n", + " \"attribute((encoding,field),3,condition).\",\n", + " \"entity(scale,0,4).\",\n", + " \"attribute((scale,channel),4,y).\",\n", + " \"attribute((scale,type),4,linear).\",\n", + " \"attribute((scale,zero),4,true).\",\n", + " \"entity(scale,0,5).\",\n", + " \"attribute((scale,channel),5,color).\",\n", + " \"attribute((scale,type),5,categorical).\",\n", + "]\n", "spec = facts_to_dict(facts)\n", "pprint(spec)" ] }, { "cell_type": "code", - "execution_count": 64, + "execution_count": 188, "metadata": {}, "outputs": [ { @@ -1086,7 +1098,7 @@ }, { "data": { - "text/html": "\n
\n", + "text/html": "\n
\n", "text/plain": "alt.Chart(...)" }, "metadata": {}, @@ -1096,14 +1108,14 @@ "source": [ "base = alt.Chart(df)\n", "arc = base.mark_arc().encode(\n", - " theta=alt.Theta(field='temperature', \n", - " type='quantitative', \n", - " aggregate='count',\n", - " stack='zero',\n", - " scale=alt.Scale(type='linear', zero=True)),\n", - " color=alt.Color(field='condition', \n", - " type='nominal',\n", - " scale=alt.Scale(type='ordinal')),\n", + " theta=alt.Theta(\n", + " field=\"temperature\",\n", + " type=\"quantitative\",\n", + " aggregate=\"count\",\n", + " stack=\"zero\",\n", + " scale=alt.Scale(type=\"linear\", zero=True),\n", + " ),\n", + " color=alt.Color(field=\"condition\", type=\"nominal\", scale=alt.Scale(type=\"ordinal\")),\n", ")\n", "display_chart(arc)" ] @@ -1117,7 +1129,7 @@ }, { "cell_type": "code", - "execution_count": 65, + "execution_count": 189, "metadata": {}, "outputs": [ { @@ -1142,44 +1154,46 @@ } ], "source": [ - "facts = ['attribute(number_rows,root,100).',\n", - " 'entity(field,root,temperature).',\n", - " 'attribute((field,name),temperature,temperature).',\n", - " 'attribute((field,type),temperature,number).',\n", - " 'entity(field,root,condition).',\n", - " 'attribute((field,name),condition,condition).',\n", - " 'attribute((field,type),condition,string).',\n", - " 'entity(view,root,0).',\n", - " 'entity(mark,0,1).',\n", - " 'attribute((mark,type),1,bar).',\n", - " 'entity(encoding,1,2).',\n", - " 'attribute((encoding,channel),2,x).',\n", - " 'attribute((encoding,field),2,temperature).',\n", - " 'attribute((encoding,binning),2,10).',\n", - " 'entity(encoding,1,3).',\n", - " 'attribute((encoding,channel),3,y).',\n", - " 'attribute((encoding,aggregate),3,count).',\n", - " 'attribute((encoding,stack),3,zero).',\n", - " 'entity(encoding,1,4).',\n", - " 'attribute((encoding,channel),4,color).',\n", - " 'attribute((encoding,field),4,condition).',\n", - " 'entity(scale,0,5).',\n", - " 'attribute((scale,channel),5,x).',\n", - " 'attribute((scale,type),5,linear).',\n", - " 'entity(scale,0,6).',\n", - " 'attribute((scale,channel),6,y).',\n", - " 'attribute((scale,type),6,linear).',\n", - " 'attribute((scale,zero),6,true).',\n", - " 'entity(scale,0,7).',\n", - " 'attribute((scale,channel),7,color).',\n", - " 'attribute((scale,type),7,categorical).']\n", + "facts = [\n", + " \"attribute(number_rows,root,100).\",\n", + " \"entity(field,root,temperature).\",\n", + " \"attribute((field,name),temperature,temperature).\",\n", + " \"attribute((field,type),temperature,number).\",\n", + " \"entity(field,root,condition).\",\n", + " \"attribute((field,name),condition,condition).\",\n", + " \"attribute((field,type),condition,string).\",\n", + " \"entity(view,root,0).\",\n", + " \"entity(mark,0,1).\",\n", + " \"attribute((mark,type),1,bar).\",\n", + " \"entity(encoding,1,2).\",\n", + " \"attribute((encoding,channel),2,x).\",\n", + " \"attribute((encoding,field),2,temperature).\",\n", + " \"attribute((encoding,binning),2,10).\",\n", + " \"entity(encoding,1,3).\",\n", + " \"attribute((encoding,channel),3,y).\",\n", + " \"attribute((encoding,aggregate),3,count).\",\n", + " \"attribute((encoding,stack),3,zero).\",\n", + " \"entity(encoding,1,4).\",\n", + " \"attribute((encoding,channel),4,color).\",\n", + " \"attribute((encoding,field),4,condition).\",\n", + " \"entity(scale,0,5).\",\n", + " \"attribute((scale,channel),5,x).\",\n", + " \"attribute((scale,type),5,linear).\",\n", + " \"entity(scale,0,6).\",\n", + " \"attribute((scale,channel),6,y).\",\n", + " \"attribute((scale,type),6,linear).\",\n", + " \"attribute((scale,zero),6,true).\",\n", + " \"entity(scale,0,7).\",\n", + " \"attribute((scale,channel),7,color).\",\n", + " \"attribute((scale,type),7,categorical).\",\n", + "]\n", "spec = facts_to_dict(facts)\n", "pprint(spec)" ] }, { "cell_type": "code", - "execution_count": 66, + "execution_count": 190, "metadata": {}, "outputs": [ { @@ -1203,7 +1217,7 @@ }, { "data": { - "text/html": "\n
\n", + "text/html": "\n
\n", "text/plain": "alt.Chart(...)" }, "metadata": {}, @@ -1213,16 +1227,20 @@ "source": [ "base = alt.Chart(df)\n", "bar = base.mark_bar().encode(\n", - " x=alt.X(field='temperature', \n", - " type='quantitative',\n", - " bin=alt.Bin(maxbins=10),\n", - " scale=alt.Scale(type='linear')),\n", - " y=alt.Y(field='temperature', \n", - " type='quantitative', \n", - " aggregate='count',\n", - " stack='zero',\n", - " scale=alt.Scale(type='linear', zero=True)),\n", - " color=alt.Color(field='condition', type='nominal')\n", + " x=alt.X(\n", + " field=\"temperature\",\n", + " type=\"quantitative\",\n", + " bin=alt.Bin(maxbins=10),\n", + " scale=alt.Scale(type=\"linear\"),\n", + " ),\n", + " y=alt.Y(\n", + " field=\"temperature\",\n", + " type=\"quantitative\",\n", + " aggregate=\"count\",\n", + " stack=\"zero\",\n", + " scale=alt.Scale(type=\"linear\", zero=True),\n", + " ),\n", + " color=alt.Color(field=\"condition\", type=\"nominal\"),\n", ")\n", "display_chart(bar)" ] @@ -1236,7 +1254,7 @@ }, { "cell_type": "code", - "execution_count": 67, + "execution_count": 191, "metadata": {}, "outputs": [ { @@ -1261,44 +1279,46 @@ } ], "source": [ - "facts = ['attribute(number_rows,root,100).',\n", - " 'entity(field,root,temperature).',\n", - " 'attribute((field,name),temperature,temperature).',\n", - " 'attribute((field,type),temperature,number).',\n", - " 'entity(field,root,condition).',\n", - " 'attribute((field,name),condition,condition).',\n", - " 'attribute((field,type),condition,string).',\n", - " 'entity(view,root,0).',\n", - " 'entity(mark,0,1).',\n", - " 'attribute((mark,type),1,bar).',\n", - " 'entity(encoding,1,2).',\n", - " 'attribute((encoding,channel),2,x).',\n", - " 'attribute((encoding,aggregate),2,count).',\n", - " 'attribute((encoding,stack),2,normalize).',\n", - " 'entity(encoding,1,3).',\n", - " 'attribute((encoding,channel),3,y).',\n", - " 'attribute((encoding,field),3,temperature).',\n", - " 'attribute((encoding,binning),3,10).',\n", - " 'entity(encoding,1,4).',\n", - " 'attribute((encoding,channel),4,color).',\n", - " 'attribute((encoding,field),4,condition).',\n", - " 'entity(scale,0,5).',\n", - " 'attribute((scale,channel),5,x).',\n", - " 'attribute((scale,type),5,linear).',\n", - " 'attribute((scale,zero),5,true).',\n", - " 'entity(scale,0,6).',\n", - " 'attribute((scale,channel),6,y).',\n", - " 'attribute((scale,type),6,linear).',\n", - " 'entity(scale,0,7).',\n", - " 'attribute((scale,channel),7,color).',\n", - " 'attribute((scale,type),7,categorical).']\n", + "facts = [\n", + " \"attribute(number_rows,root,100).\",\n", + " \"entity(field,root,temperature).\",\n", + " \"attribute((field,name),temperature,temperature).\",\n", + " \"attribute((field,type),temperature,number).\",\n", + " \"entity(field,root,condition).\",\n", + " \"attribute((field,name),condition,condition).\",\n", + " \"attribute((field,type),condition,string).\",\n", + " \"entity(view,root,0).\",\n", + " \"entity(mark,0,1).\",\n", + " \"attribute((mark,type),1,bar).\",\n", + " \"entity(encoding,1,2).\",\n", + " \"attribute((encoding,channel),2,x).\",\n", + " \"attribute((encoding,aggregate),2,count).\",\n", + " \"attribute((encoding,stack),2,normalize).\",\n", + " \"entity(encoding,1,3).\",\n", + " \"attribute((encoding,channel),3,y).\",\n", + " \"attribute((encoding,field),3,temperature).\",\n", + " \"attribute((encoding,binning),3,10).\",\n", + " \"entity(encoding,1,4).\",\n", + " \"attribute((encoding,channel),4,color).\",\n", + " \"attribute((encoding,field),4,condition).\",\n", + " \"entity(scale,0,5).\",\n", + " \"attribute((scale,channel),5,x).\",\n", + " \"attribute((scale,type),5,linear).\",\n", + " \"attribute((scale,zero),5,true).\",\n", + " \"entity(scale,0,6).\",\n", + " \"attribute((scale,channel),6,y).\",\n", + " \"attribute((scale,type),6,linear).\",\n", + " \"entity(scale,0,7).\",\n", + " \"attribute((scale,channel),7,color).\",\n", + " \"attribute((scale,type),7,categorical).\",\n", + "]\n", "spec = facts_to_dict(facts)\n", "pprint(spec)" ] }, { "cell_type": "code", - "execution_count": 68, + "execution_count": 192, "metadata": {}, "outputs": [ { @@ -1322,7 +1342,7 @@ }, { "data": { - "text/html": "\n
\n", + "text/html": "\n
\n", "text/plain": "alt.Chart(...)" }, "metadata": {}, @@ -1332,16 +1352,20 @@ "source": [ "base = alt.Chart(df)\n", "bar = base.mark_bar().encode(\n", - " x=alt.X(field='temperature', \n", - " type='quantitative', \n", - " aggregate='count', \n", - " stack='normalize',\n", - " scale=alt.Scale(type='linear', zero=True)),\n", - " y=alt.Y(field='temperature', \n", - " type='quantitative',\n", - " bin=alt.Bin(maxbins=10),\n", - " scale=alt.Scale(type='linear')),\n", - " color=alt.Color(field='condition', type='nominal')\n", + " x=alt.X(\n", + " field=\"temperature\",\n", + " type=\"quantitative\",\n", + " aggregate=\"count\",\n", + " stack=\"normalize\",\n", + " scale=alt.Scale(type=\"linear\", zero=True),\n", + " ),\n", + " y=alt.Y(\n", + " field=\"temperature\",\n", + " type=\"quantitative\",\n", + " bin=alt.Bin(maxbins=10),\n", + " scale=alt.Scale(type=\"linear\"),\n", + " ),\n", + " color=alt.Color(field=\"condition\", type=\"nominal\"),\n", ")\n", "display_chart(bar)" ] @@ -1362,7 +1386,7 @@ }, { "cell_type": "code", - "execution_count": 69, + "execution_count": 193, "metadata": {}, "outputs": [ { @@ -1382,33 +1406,35 @@ } ], "source": [ - "facts = ['attribute(number_rows,root,100).',\n", - " 'entity(field,root,temperature).',\n", - " 'attribute((field,name),temperature,temperature).',\n", - " 'attribute((field,type),temperature,number).',\n", - " 'entity(view,root,0).',\n", - " 'entity(mark,0,1).',\n", - " 'attribute((mark,type),1,bar).',\n", - " 'entity(encoding,1,2).',\n", - " 'attribute((encoding,channel),2,x).',\n", - " 'attribute((encoding,aggregate),2,mean).',\n", - " 'attribute((encoding,field),2,temperature).',\n", - " 'entity(mark,0,3).',\n", - " 'attribute((mark,type),3,tick).',\n", - " 'entity(encoding,3,4).',\n", - " 'attribute((encoding,channel),4,x).',\n", - " 'attribute((encoding,field),4,temperature).',\n", - " 'entity(scale,0,5).',\n", - " 'attribute((scale,channel),5,x).',\n", - " 'attribute((scale,type),5,linear).',\n", - " 'attribute((scale,zero),5,true).']\n", + "facts = [\n", + " \"attribute(number_rows,root,100).\",\n", + " \"entity(field,root,temperature).\",\n", + " \"attribute((field,name),temperature,temperature).\",\n", + " \"attribute((field,type),temperature,number).\",\n", + " \"entity(view,root,0).\",\n", + " \"entity(mark,0,1).\",\n", + " \"attribute((mark,type),1,bar).\",\n", + " \"entity(encoding,1,2).\",\n", + " \"attribute((encoding,channel),2,x).\",\n", + " \"attribute((encoding,aggregate),2,mean).\",\n", + " \"attribute((encoding,field),2,temperature).\",\n", + " \"entity(mark,0,3).\",\n", + " \"attribute((mark,type),3,tick).\",\n", + " \"entity(encoding,3,4).\",\n", + " \"attribute((encoding,channel),4,x).\",\n", + " \"attribute((encoding,field),4,temperature).\",\n", + " \"entity(scale,0,5).\",\n", + " \"attribute((scale,channel),5,x).\",\n", + " \"attribute((scale,type),5,linear).\",\n", + " \"attribute((scale,zero),5,true).\",\n", + "]\n", "spec = facts_to_dict(facts)\n", "pprint(spec)" ] }, { "cell_type": "code", - "execution_count": 70, + "execution_count": 194, "metadata": {}, "outputs": [ { @@ -1430,7 +1456,7 @@ }, { "data": { - "text/html": "\n
\n", + "text/html": "\n
\n", "text/plain": "alt.LayerChart(...)" }, "metadata": {}, @@ -1440,15 +1466,19 @@ "source": [ "base = alt.Chart(df)\n", "bar = base.mark_bar().encode(\n", - " x=alt.X(field='temperature', \n", - " type='quantitative',\n", - " aggregate='mean',\n", - " scale=alt.Scale(type='linear', zero=True)),\n", + " x=alt.X(\n", + " field=\"temperature\",\n", + " type=\"quantitative\",\n", + " aggregate=\"mean\",\n", + " scale=alt.Scale(type=\"linear\", zero=True),\n", + " ),\n", ")\n", "tick = base.mark_tick().encode(\n", - " x=alt.X(field='temperature', \n", - " type='quantitative',\n", - " scale=alt.Scale(type='linear', zero=True)),\n", + " x=alt.X(\n", + " field=\"temperature\",\n", + " type=\"quantitative\",\n", + " scale=alt.Scale(type=\"linear\", zero=True),\n", + " ),\n", ")\n", "display_chart(bar + tick)" ] @@ -1469,7 +1499,7 @@ }, { "cell_type": "code", - "execution_count": 71, + "execution_count": 195, "metadata": {}, "outputs": [ { @@ -1490,41 +1520,43 @@ } ], "source": [ - "facts = ['attribute(number_rows,root,100).',\n", - " 'entity(field,root,temperature).',\n", - " 'attribute((field,name),temperature,temperature).',\n", - " 'attribute((field,type),temperature,number).',\n", - " 'entity(field,root,wind).',\n", - " 'attribute((field,name),wind,wind).',\n", - " 'attribute((field,type),wind,number).',\n", - " 'entity(field,root,condition).',\n", - " 'attribute((field,name),condition,condition).',\n", - " 'attribute((field,type),condition,string).',\n", - " 'entity(view,root,0).',\n", - " 'entity(mark,0,1).',\n", - " 'attribute((mark,type),1,point).',\n", - " 'entity(encoding,1,2).',\n", - " 'attribute((encoding,channel),2,x).',\n", - " 'attribute((encoding,field),2,temperature).',\n", - " 'entity(encoding,1,3).',\n", - " 'attribute((encoding,channel),3,y).',\n", - " 'attribute((encoding,field),3,wind).',\n", - " 'entity(scale,0,4).',\n", - " 'attribute((scale,channel),4,x).',\n", - " 'attribute((scale,type),4,linear).',\n", - " 'entity(scale,0,5).',\n", - " 'attribute((scale,channel),5,y).',\n", - " 'attribute((scale,type),5,linear).',\n", - " 'entity(facet,0,6).',\n", - " 'attribute((facet,channel),6,col).',\n", - " 'attribute((facet,field),6,condition).']\n", + "facts = [\n", + " \"attribute(number_rows,root,100).\",\n", + " \"entity(field,root,temperature).\",\n", + " \"attribute((field,name),temperature,temperature).\",\n", + " \"attribute((field,type),temperature,number).\",\n", + " \"entity(field,root,wind).\",\n", + " \"attribute((field,name),wind,wind).\",\n", + " \"attribute((field,type),wind,number).\",\n", + " \"entity(field,root,condition).\",\n", + " \"attribute((field,name),condition,condition).\",\n", + " \"attribute((field,type),condition,string).\",\n", + " \"entity(view,root,0).\",\n", + " \"entity(mark,0,1).\",\n", + " \"attribute((mark,type),1,point).\",\n", + " \"entity(encoding,1,2).\",\n", + " \"attribute((encoding,channel),2,x).\",\n", + " \"attribute((encoding,field),2,temperature).\",\n", + " \"entity(encoding,1,3).\",\n", + " \"attribute((encoding,channel),3,y).\",\n", + " \"attribute((encoding,field),3,wind).\",\n", + " \"entity(scale,0,4).\",\n", + " \"attribute((scale,channel),4,x).\",\n", + " \"attribute((scale,type),4,linear).\",\n", + " \"entity(scale,0,5).\",\n", + " \"attribute((scale,channel),5,y).\",\n", + " \"attribute((scale,type),5,linear).\",\n", + " \"entity(facet,0,6).\",\n", + " \"attribute((facet,channel),6,col).\",\n", + " \"attribute((facet,field),6,condition).\",\n", + "]\n", "spec = facts_to_dict(facts)\n", "pprint(spec)" ] }, { "cell_type": "code", - "execution_count": 72, + "execution_count": 196, "metadata": {}, "outputs": [ { @@ -1541,7 +1573,7 @@ }, { "data": { - "text/html": "\n
\n", + "text/html": "\n
\n", "text/plain": "alt.FacetChart(...)" }, "metadata": {}, @@ -1551,12 +1583,10 @@ "source": [ "base = alt.Chart(df)\n", "point = base.mark_point().encode(\n", - " x=alt.X(field='temperature', type='quantitative'),\n", - " y=alt.Y(field='wind', type='quantitative')\n", - ")\n", - "facet = point.facet(\n", - " column=alt.Column(field='condition', type='nominal')\n", + " x=alt.X(field=\"temperature\", type=\"quantitative\"),\n", + " y=alt.Y(field=\"wind\", type=\"quantitative\"),\n", ")\n", + "facet = point.facet(column=alt.Column(field=\"condition\", type=\"nominal\"))\n", "display_chart(facet)" ] }, @@ -1569,7 +1599,7 @@ }, { "cell_type": "code", - "execution_count": 73, + "execution_count": 197, "metadata": {}, "outputs": [ { @@ -1590,42 +1620,44 @@ } ], "source": [ - "facts = ['attribute(number_rows,root,100).',\n", - " 'entity(field,root,temperature).',\n", - " 'attribute((field,name),temperature,temperature).',\n", - " 'attribute((field,type),temperature,number).',\n", - " 'entity(field,root,wind).',\n", - " 'attribute((field,name),wind,wind).',\n", - " 'attribute((field,type),wind,number).',\n", - " 'entity(field,root,condition).',\n", - " 'attribute((field,name),condition,condition).',\n", - " 'attribute((field,type),condition,string).',\n", - " 'entity(view,root,0).',\n", - " 'entity(mark,0,1).',\n", - " 'attribute((mark,type),1,point).',\n", - " 'entity(encoding,1,2).',\n", - " 'attribute((encoding,channel),2,x).',\n", - " 'attribute((encoding,field),2,condition).',\n", - " 'entity(encoding,1,3).',\n", - " 'attribute((encoding,channel),3,y).',\n", - " 'attribute((encoding,field),3,wind).',\n", - " 'entity(scale,0,4).',\n", - " 'attribute((scale,channel),4,x).',\n", - " 'attribute((scale,type),4,ordinal).',\n", - " 'entity(scale,0,5).',\n", - " 'attribute((scale,channel),5,y).',\n", - " 'attribute((scale,type),5,linear).',\n", - " 'entity(facet,0,6).',\n", - " 'attribute((facet,channel),6,col).',\n", - " 'attribute((facet,field),6,temperature).',\n", - " 'attribute((facet,binning),6,10).']\n", + "facts = [\n", + " \"attribute(number_rows,root,100).\",\n", + " \"entity(field,root,temperature).\",\n", + " \"attribute((field,name),temperature,temperature).\",\n", + " \"attribute((field,type),temperature,number).\",\n", + " \"entity(field,root,wind).\",\n", + " \"attribute((field,name),wind,wind).\",\n", + " \"attribute((field,type),wind,number).\",\n", + " \"entity(field,root,condition).\",\n", + " \"attribute((field,name),condition,condition).\",\n", + " \"attribute((field,type),condition,string).\",\n", + " \"entity(view,root,0).\",\n", + " \"entity(mark,0,1).\",\n", + " \"attribute((mark,type),1,point).\",\n", + " \"entity(encoding,1,2).\",\n", + " \"attribute((encoding,channel),2,x).\",\n", + " \"attribute((encoding,field),2,condition).\",\n", + " \"entity(encoding,1,3).\",\n", + " \"attribute((encoding,channel),3,y).\",\n", + " \"attribute((encoding,field),3,wind).\",\n", + " \"entity(scale,0,4).\",\n", + " \"attribute((scale,channel),4,x).\",\n", + " \"attribute((scale,type),4,ordinal).\",\n", + " \"entity(scale,0,5).\",\n", + " \"attribute((scale,channel),5,y).\",\n", + " \"attribute((scale,type),5,linear).\",\n", + " \"entity(facet,0,6).\",\n", + " \"attribute((facet,channel),6,col).\",\n", + " \"attribute((facet,field),6,temperature).\",\n", + " \"attribute((facet,binning),6,10).\",\n", + "]\n", "spec = facts_to_dict(facts)\n", "pprint(spec)" ] }, { "cell_type": "code", - "execution_count": 74, + "execution_count": 198, "metadata": {}, "outputs": [ { @@ -1648,7 +1680,7 @@ }, { "data": { - "text/html": "\n
\n", + "text/html": "\n
\n", "text/plain": "alt.FacetChart(...)" }, "metadata": {}, @@ -1658,11 +1690,11 @@ "source": [ "base = alt.Chart(df)\n", "point = base.mark_point().encode(\n", - " x=alt.X(field='condition', type='nominal', scale=alt.Scale(type='ordinal')),\n", - " y=alt.Y(field='wind', type='quantitative', scale=alt.Scale(type='linear'))\n", + " x=alt.X(field=\"condition\", type=\"nominal\", scale=alt.Scale(type=\"ordinal\")),\n", + " y=alt.Y(field=\"wind\", type=\"quantitative\", scale=alt.Scale(type=\"linear\")),\n", ")\n", "facet = point.facet(\n", - " column=alt.Column(field='temperature', type='quantitative', bin=alt.Bin(maxbins=10))\n", + " column=alt.Column(field=\"temperature\", type=\"quantitative\", bin=alt.Bin(maxbins=10))\n", ")\n", "display_chart(facet)" ] @@ -1683,7 +1715,7 @@ }, { "cell_type": "code", - "execution_count": 75, + "execution_count": 199, "metadata": {}, "outputs": [ { @@ -1705,46 +1737,48 @@ } ], "source": [ - "facts = ['attribute(number_rows,root,100).',\n", - " 'entity(field,root,temperature).',\n", - " 'attribute((field,name),temperature,temperature).',\n", - " 'attribute((field,type),temperature,number).',\n", - " 'entity(field,root,condition).',\n", - " 'attribute((field,name),condition,condition).',\n", - " 'attribute((field,type),condition,string).',\n", - " 'entity(view,root,0).',\n", - " 'entity(mark,0,1).',\n", - " 'attribute((mark,type),1,tick).',\n", - " 'entity(encoding,1,2).',\n", - " 'attribute((encoding,channel),2,y).',\n", - " 'attribute((encoding,field),2,temperature).',\n", - " 'entity(scale,0,3).',\n", - " 'attribute((scale,channel),3,y).',\n", - " 'attribute((scale,type),3,linear).',\n", - " 'attribute((scale,zero),3,true).',\n", - " 'entity(view,root,4).',\n", - " 'entity(mark,4,5).',\n", - " 'attribute((mark,type),5,bar).',\n", - " 'entity(encoding,5,6).',\n", - " 'attribute((encoding,channel),6,x).',\n", - " 'attribute((encoding,field),6,condition).',\n", - " 'entity(encoding,5,7).',\n", - " 'attribute((encoding,channel),7,y).',\n", - " 'attribute((encoding,aggregate),7,count).',\n", - " 'entity(scale,4,8).',\n", - " 'attribute((scale,channel),8,x).',\n", - " 'attribute((scale,type),8,ordinal).',\n", - " 'entity(scale,4,9).',\n", - " 'attribute((scale,channel),9,y).',\n", - " 'attribute((scale,type),9,linear).',\n", - " 'attribute((scale,zero),9,true).']\n", + "facts = [\n", + " \"attribute(number_rows,root,100).\",\n", + " \"entity(field,root,temperature).\",\n", + " \"attribute((field,name),temperature,temperature).\",\n", + " \"attribute((field,type),temperature,number).\",\n", + " \"entity(field,root,condition).\",\n", + " \"attribute((field,name),condition,condition).\",\n", + " \"attribute((field,type),condition,string).\",\n", + " \"entity(view,root,0).\",\n", + " \"entity(mark,0,1).\",\n", + " \"attribute((mark,type),1,tick).\",\n", + " \"entity(encoding,1,2).\",\n", + " \"attribute((encoding,channel),2,y).\",\n", + " \"attribute((encoding,field),2,temperature).\",\n", + " \"entity(scale,0,3).\",\n", + " \"attribute((scale,channel),3,y).\",\n", + " \"attribute((scale,type),3,linear).\",\n", + " \"attribute((scale,zero),3,true).\",\n", + " \"entity(view,root,4).\",\n", + " \"entity(mark,4,5).\",\n", + " \"attribute((mark,type),5,bar).\",\n", + " \"entity(encoding,5,6).\",\n", + " \"attribute((encoding,channel),6,x).\",\n", + " \"attribute((encoding,field),6,condition).\",\n", + " \"entity(encoding,5,7).\",\n", + " \"attribute((encoding,channel),7,y).\",\n", + " \"attribute((encoding,aggregate),7,count).\",\n", + " \"entity(scale,4,8).\",\n", + " \"attribute((scale,channel),8,x).\",\n", + " \"attribute((scale,type),8,ordinal).\",\n", + " \"entity(scale,4,9).\",\n", + " \"attribute((scale,channel),9,y).\",\n", + " \"attribute((scale,type),9,linear).\",\n", + " \"attribute((scale,zero),9,true).\",\n", + "]\n", "spec = facts_to_dict(facts)\n", "pprint(spec)" ] }, { "cell_type": "code", - "execution_count": 76, + "execution_count": 200, "metadata": {}, "outputs": [ { @@ -1768,7 +1802,7 @@ }, { "data": { - "text/html": "\n
\n", + "text/html": "\n
\n", "text/plain": "alt.HConcatChart(...)" }, "metadata": {}, @@ -1779,13 +1813,17 @@ "base = alt.Chart(df)\n", "\n", "tick = base.mark_tick().encode(\n", - " y=alt.Y(field='temperature', type='quantitative', scale=alt.Scale(type='linear', zero=True))\n", + " y=alt.Y(\n", + " field=\"temperature\",\n", + " type=\"quantitative\",\n", + " scale=alt.Scale(type=\"linear\", zero=True),\n", + " )\n", ")\n", "view_1 = tick\n", "\n", "bar = base.mark_bar().encode(\n", - " x=alt.X(field='condition', type='nominal', scale=alt.Scale(type='ordinal')),\n", - " y=alt.Y(field='condition', type='nominal', aggregate='count')\n", + " x=alt.X(field=\"condition\", type=\"nominal\", scale=alt.Scale(type=\"ordinal\")),\n", + " y=alt.Y(field=\"condition\", type=\"nominal\", aggregate=\"count\"),\n", ")\n", "view_2 = bar\n", "\n", @@ -1801,7 +1839,7 @@ }, { "cell_type": "code", - "execution_count": 77, + "execution_count": 201, "metadata": {}, "outputs": [ { @@ -1824,43 +1862,45 @@ } ], "source": [ - "facts = ['attribute(number_rows,root,100).',\n", - " 'entity(field,root,temperature).',\n", - " 'attribute((field,name),temperature,temperature).',\n", - " 'attribute((field,type),temperature,number).',\n", - " 'entity(field,root,condition).',\n", - " 'attribute((field,name),condition,condition).',\n", - " 'attribute((field,type),condition,string).',\n", - " 'entity(view,root,0).',\n", - " 'entity(mark,0,1).',\n", - " 'attribute((mark,type),1,tick).',\n", - " 'entity(encoding,1,2).',\n", - " 'attribute((encoding,channel),2,y).',\n", - " 'attribute((encoding,field),2,temperature).',\n", - " 'entity(view,root,3).',\n", - " 'entity(mark,3,4).',\n", - " 'attribute((mark,type),4,bar).',\n", - " 'entity(encoding,4,5).',\n", - " 'attribute((encoding,channel),5,y).',\n", - " 'attribute((encoding,field),5,temperature).',\n", - " 'attribute((encoding,aggregate),5,mean).',\n", - " 'entity(encoding,4,6).',\n", - " 'attribute((encoding,channel),6,x).',\n", - " 'attribute((encoding,field),6,condition).',\n", - " 'entity(scale,3,7).',\n", - " 'attribute((scale,channel),7,x).',\n", - " 'attribute((scale,type),7,ordinal).',\n", - " 'entity(scale,root,8).',\n", - " 'attribute((scale,channel),8,y).',\n", - " 'attribute((scale,type),8,linear).',\n", - " 'attribute((scale,zero),8,true).']\n", + "facts = [\n", + " \"attribute(number_rows,root,100).\",\n", + " \"entity(field,root,temperature).\",\n", + " \"attribute((field,name),temperature,temperature).\",\n", + " \"attribute((field,type),temperature,number).\",\n", + " \"entity(field,root,condition).\",\n", + " \"attribute((field,name),condition,condition).\",\n", + " \"attribute((field,type),condition,string).\",\n", + " \"entity(view,root,0).\",\n", + " \"entity(mark,0,1).\",\n", + " \"attribute((mark,type),1,tick).\",\n", + " \"entity(encoding,1,2).\",\n", + " \"attribute((encoding,channel),2,y).\",\n", + " \"attribute((encoding,field),2,temperature).\",\n", + " \"entity(view,root,3).\",\n", + " \"entity(mark,3,4).\",\n", + " \"attribute((mark,type),4,bar).\",\n", + " \"entity(encoding,4,5).\",\n", + " \"attribute((encoding,channel),5,y).\",\n", + " \"attribute((encoding,field),5,temperature).\",\n", + " \"attribute((encoding,aggregate),5,mean).\",\n", + " \"entity(encoding,4,6).\",\n", + " \"attribute((encoding,channel),6,x).\",\n", + " \"attribute((encoding,field),6,condition).\",\n", + " \"entity(scale,3,7).\",\n", + " \"attribute((scale,channel),7,x).\",\n", + " \"attribute((scale,type),7,ordinal).\",\n", + " \"entity(scale,root,8).\",\n", + " \"attribute((scale,channel),8,y).\",\n", + " \"attribute((scale,type),8,linear).\",\n", + " \"attribute((scale,zero),8,true).\",\n", + "]\n", "spec = facts_to_dict(facts)\n", "pprint(spec)" ] }, { "cell_type": "code", - "execution_count": 78, + "execution_count": 202, "metadata": {}, "outputs": [ { @@ -1882,7 +1922,7 @@ }, { "data": { - "text/html": "\n
\n", + "text/html": "\n
\n", "text/plain": "alt.HConcatChart(...)" }, "metadata": {}, @@ -1892,29 +1932,140 @@ "source": [ "base = alt.Chart(df)\n", "\n", - "tick = base.mark_tick().encode(\n", - " y=alt.Y(field='temperature', type='quantitative')\n", - ")\n", + "tick = base.mark_tick().encode(y=alt.Y(field=\"temperature\", type=\"quantitative\"))\n", "view_1 = tick\n", "\n", "bar = base.mark_bar().encode(\n", - " x=alt.X(field='condition', type='nominal'),\n", - " y=alt.Y(field='temperature', type='quantitative', aggregate='mean')\n", + " x=alt.X(field=\"condition\", type=\"nominal\"),\n", + " y=alt.Y(field=\"temperature\", type=\"quantitative\", aggregate=\"mean\"),\n", ")\n", "view_2 = bar\n", - "chart = alt.hconcat(view_1, view_2).resolve_scale(\n", - " y='shared'\n", - ")\n", + "chart = alt.hconcat(view_1, view_2).resolve_scale(y=\"shared\")\n", "\n", "display_chart(chart)" ] }, { "cell_type": "code", - "execution_count": 78, + "execution_count": 203, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "from typing import Mapping, Generic, TypeVar\n", + "from abc import ABC, abstractmethod\n", + "\n", + "T = TypeVar(\"T\")\n", + "SpecProperty = str | int | float | bool | None | dict\n", + "\n", + "\n", + "class BaseRenderer(ABC, Generic[T]):\n", + " \"\"\"\n", + " Base class for all renderers.\n", + " \"\"\"\n", + "\n", + " def render(self, spec: Mapping) -> T:\n", + " \"\"\"\n", + " Render a dictionary-based specification\n", + " into a concrete rendering product of type `T`.\n", + " The rendering object's actual type depends on the concrete renderer.\n", + "\n", + " :param spec: dictionary-based specification\n", + " :return: product of the rendering\n", + " \"\"\"\n", + "\n", + " def visit_mapping(\n", + " dct: Mapping, path: tuple[str | int, ...] = (), acc: T = self._initial\n", + " ):\n", + " \"\"\"\n", + " Recursively visit a dictionary-based specification.\n", + "\n", + " :param dct: dictionary-based specification\n", + " :param path: path to the current node\n", + " :param acc: accumulated rendering product\n", + " \"\"\"\n", + " for key, value in dct.items():\n", + " if isinstance(value, dict):\n", + " # if the current value does not have further dicts in it, then call the visitor\n", + " if not any(isinstance(v, dict) for v in value.values()):\n", + " acc = self._visitor(value, path + (key,), acc)\n", + " else:\n", + " visit_mapping(value, path + (key,), acc)\n", + " elif isinstance(value, list):\n", + " for i, item in enumerate(value):\n", + " visit_mapping(item, path + (key, i), acc)\n", + " else:\n", + " acc = self._visitor(value, path + (key,), acc)\n", + "\n", + " return visit_mapping(spec)\n", + "\n", + " @property\n", + " @abstractmethod\n", + " def _initial(self) -> T:\n", + " raise NotImplementedError\n", + "\n", + " @abstractmethod\n", + " def _visitor(self, value: SpecProperty, path: tuple[str | int, ...], acc: T) -> T:\n", + " raise NotImplementedError\n", + "\n", + "\n", + "class VegaLiteRenderer(BaseRenderer):\n", + " @property\n", + " def _initial(self) -> T:\n", + " return {}\n", + "\n", + " def _visitor(self, value: SpecProperty, path: tuple[str | int, ...], acc: T) -> T:\n", + " print(path, value)\n", + " return acc" + ] + }, + { + "cell_type": "code", + "execution_count": 205, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'number_rows': 100, 'field': [{'name': 'temperature', 'type': 'number'}, {'name': 'condition', 'type': 'string'}], 'view': [{'mark': [{'type': 'tick', 'encoding': [{'channel': 'y', 'field': 'temperature'}]}]}, {'mark': [{'type': 'bar', 'encoding': [{'channel': 'y', 'field': 'temperature', 'aggregate': 'mean'}, {'channel': 'x', 'field': 'condition'}]}], 'scale': [{'channel': 'x', 'type': 'ordinal'}]}], 'scale': [{'channel': 'y', 'type': 'linear', 'zero': 'true'}]}\n", + "('number_rows',) 100\n", + "('field', 0, 'name') temperature\n", + "('field', 0, 'type') number\n", + "('field', 1, 'name') condition\n", + "('field', 1, 'type') string\n", + "('view', 0, 'mark', 0, 'type') tick\n", + "('view', 0, 'mark', 0, 'encoding', 0, 'channel') y\n", + "('view', 0, 'mark', 0, 'encoding', 0, 'field') temperature\n", + "('view', 1, 'mark', 0, 'type') bar\n", + "('view', 1, 'mark', 0, 'encoding', 0, 'channel') y\n", + "('view', 1, 'mark', 0, 'encoding', 0, 'field') temperature\n", + "('view', 1, 'mark', 0, 'encoding', 0, 'aggregate') mean\n", + "('view', 1, 'mark', 0, 'encoding', 1, 'channel') x\n", + "('view', 1, 'mark', 0, 'encoding', 1, 'field') condition\n", + "('view', 1, 'scale', 0, 'channel') x\n", + "('view', 1, 'scale', 0, 'type') ordinal\n", + "('scale', 0, 'channel') y\n", + "('scale', 0, 'type') linear\n", + "('scale', 0, 'zero') true\n" + ] + } + ], + "source": [ + "vl = VegaLiteRenderer()\n", + "print(spec)\n", + "vl.render(spec)" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + } } ], "metadata": { diff --git a/draco/renderer.py b/draco/renderer.py new file mode 100644 index 00000000..dc98d9f5 --- /dev/null +++ b/draco/renderer.py @@ -0,0 +1,155 @@ +from abc import ABC, abstractmethod +from dataclasses import dataclass, field +from typing import Generic, Optional, TypeVar + +from draco.utils import dict_value_by_path + +T = TypeVar("T") +SpecProperty = str | int | float | bool | None | dict | list + + +@dataclass(frozen=True, kw_only=True) +class VisitedItem(Generic[T]): + value: SpecProperty + path: tuple[int | str, ...] + acc: T = field(repr=False) + spec: dict = field(repr=False) + + @property + def parent(self) -> Optional["VisitedItem"]: + has_parent = len(self.path) > 0 + if has_parent: + parent_path = self.path[:-1] + value = dict_value_by_path(self.spec, parent_path) + return VisitedItem( + value=value, path=parent_path, acc=self.acc, spec=self.spec + ) + return None + + +class BaseRenderer(ABC, Generic[T]): + """ + Base class for all renderers. + """ + + def render(self, spec: dict) -> T: + """ + Render a dictionary-based specification + into a concrete rendering product of type `T`. + The rendering object's actual type depends on the concrete renderer. + + :param spec: dictionary-based specification + :return: product of the rendering + """ + + def traverse(dct: dict, path: tuple[str | int, ...], acc: T): + """ + Recursively visit a dictionary-based specification. + + :param dct: dictionary-based specification + :param path: path to the current node + :param acc: accumulated rendering product + :return: the most recent rendering product + """ + has_complex_children = any( + isinstance(v, dict) or isinstance(v, list) for v in dct.values() + ) + if not has_complex_children: + return self._visitor( + VisitedItem(value=dct, path=path, acc=acc, spec=spec) + ) + + for key, value in dct.items(): + if isinstance(value, dict): + acc = traverse(value, path + (key,), acc) + elif isinstance(value, list): + for i, item in enumerate(value): + acc = traverse(item, path + (key, i), acc) + else: + acc = self._visitor( + VisitedItem(value=value, path=path + (key,), acc=acc, spec=spec) + ) + return acc + + return traverse(dct=spec, path=(), acc=self._initial) + + @property + @abstractmethod + def _initial(self) -> T: + """ + :return: The initial rendering product to start with. + """ + raise NotImplementedError + + @abstractmethod + def _visitor(self, item: VisitedItem[T]) -> T: + """ + The callback to be invoked for each visited item of the specification. + Should be implemented by concrete renderers to produce the rendering product + step-by-step based on the contents of the supplied `payload`. + + :param item: the visited item + :return: the updated rendering product + """ + raise NotImplementedError + + +class VegaLiteRenderer(BaseRenderer[dict]): + @property + def _initial(self) -> dict: + return {"x": 0} + + def _visitor(self, item: VisitedItem) -> dict: + print(item) + return {"x": item.acc["x"] + 1} + + +if __name__ == "__main__": + from draco.fact_utils import answer_set_to_dict + from draco.run import run_clingo + + def facts_to_dict(facts: list[str]): + result = run_clingo(facts) + return answer_set_to_dict(next(result).answer_set) + + facts = [ + "attribute(number_rows,root,100).", + "entity(field,root,temperature).", + "attribute((field,name),temperature,temperature).", + "attribute((field,type),temperature,number).", + "entity(field,root,condition).", + "attribute((field,name),condition,condition).", + "attribute((field,type),condition,string).", + "entity(view,root,0).", + "entity(mark,0,1).", + "attribute((mark,type),1,tick).", + "entity(encoding,1,2).", + "attribute((encoding,channel),2,y).", + "attribute((encoding,field),2,temperature).", + "entity(view,root,3).", + "entity(mark,3,4).", + "attribute((mark,type),4,bar).", + "entity(encoding,4,5).", + "attribute((encoding,channel),5,y).", + "attribute((encoding,field),5,temperature).", + "attribute((encoding,aggregate),5,mean).", + "entity(encoding,4,6).", + "attribute((encoding,channel),6,x).", + "attribute((encoding,field),6,condition).", + "entity(scale,3,7).", + "attribute((scale,channel),7,x).", + "attribute((scale,type),7,ordinal).", + "entity(scale,root,8).", + "attribute((scale,channel),8,y).", + "attribute((scale,type),8,linear).", + "attribute((scale,zero),8,true).", + ] + spec = facts_to_dict(facts) + from pprint import pprint + + pprint(spec) + print() + + vl = VegaLiteRenderer() + product = vl.render(dict(spec)) + print(product) diff --git a/draco/utils.py b/draco/utils.py index b3b79c9b..3c4b400b 100644 --- a/draco/utils.py +++ b/draco/utils.py @@ -3,3 +3,9 @@ def dict_union(*args: dict): return dict(chain.from_iterable(d.items() for d in args)) + + +def dict_value_by_path(d: dict, path: tuple): + for key in path: + d = d[key] + return d From 50e0dfd3d75e37a5f2654c5fb98c3d866949ebb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Tue, 8 Nov 2022 14:34:03 +0100 Subject: [PATCH 03/45] refactor: extract renderer base --- docs/facts/examples-vl.ipynb | 1337 ++++++++++++++++++++++---- draco/renderer.py | 155 --- draco/renderer/__init__.py | 0 draco/renderer/base_renderer.py | 150 +++ draco/renderer/vega_lite.py | 0 draco/renderer/vega_lite_renderer.py | 75 ++ 6 files changed, 1367 insertions(+), 350 deletions(-) delete mode 100644 draco/renderer.py create mode 100644 draco/renderer/__init__.py create mode 100644 draco/renderer/base_renderer.py create mode 100644 draco/renderer/vega_lite.py create mode 100644 draco/renderer/vega_lite_renderer.py diff --git a/docs/facts/examples-vl.ipynb b/docs/facts/examples-vl.ipynb index 026d3970..81532108 100644 --- a/docs/facts/examples-vl.ipynb +++ b/docs/facts/examples-vl.ipynb @@ -11,7 +11,7 @@ }, { "cell_type": "code", - "execution_count": 164, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -24,7 +24,7 @@ }, { "cell_type": "code", - "execution_count": 165, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -35,7 +35,7 @@ }, { "cell_type": "code", - "execution_count": 166, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -53,7 +53,7 @@ }, { "cell_type": "code", - "execution_count": 167, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -81,15 +81,86 @@ }, { "cell_type": "code", - "execution_count": 168, + "execution_count": 5, "metadata": {}, "outputs": [ { "data": { - "text/plain": " temperature wind precipitation condition\n0 15.949649 44.064475 39.571021 sun\n1 35.804103 57.347114 51.104157 snow\n2 34.390488 96.360482 40.969804 drizzle\n3 7.204886 25.146399 85.490179 drizzle\n4 19.552840 57.883961 73.697679 sun", - "text/html": "
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
temperaturewindprecipitationcondition
015.94964944.06447539.571021sun
135.80410357.34711451.104157snow
234.39048896.36048240.969804drizzle
37.20488625.14639985.490179drizzle
419.55284057.88396173.697679sun
\n
" + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
temperaturewindprecipitationcondition
017.89365378.75685641.611246rain
15.62281825.42199974.905551rain
223.3902099.84610381.335364rain
320.88955427.53521327.654932drizzle
433.91026297.91032836.534943snow
\n", + "
" + ], + "text/plain": [ + " temperature wind precipitation condition\n", + "0 17.893653 78.756856 41.611246 rain\n", + "1 5.622818 25.421999 74.905551 rain\n", + "2 23.390209 9.846103 81.335364 rain\n", + "3 20.889554 27.535213 27.654932 drizzle\n", + "4 33.910262 97.910328 36.534943 snow" + ] }, - "execution_count": 168, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -114,7 +185,7 @@ }, { "cell_type": "code", - "execution_count": 169, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -151,7 +222,7 @@ }, { "cell_type": "code", - "execution_count": 170, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -176,8 +247,66 @@ }, { "data": { - "text/html": "\n
\n", - "text/plain": "alt.Chart(...)" + "text/html": [ + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.Chart(...)" + ] }, "metadata": {}, "output_type": "display_data" @@ -200,7 +329,7 @@ }, { "cell_type": "code", - "execution_count": 171, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -237,7 +366,7 @@ }, { "cell_type": "code", - "execution_count": 172, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -255,8 +384,66 @@ }, { "data": { - "text/html": "\n
\n", - "text/plain": "alt.Chart(...)" + "text/html": [ + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.Chart(...)" + ] }, "metadata": {}, "output_type": "display_data" @@ -279,7 +466,7 @@ }, { "cell_type": "code", - "execution_count": 173, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -334,7 +521,7 @@ }, { "cell_type": "code", - "execution_count": 174, + "execution_count": 11, "metadata": {}, "outputs": [ { @@ -355,8 +542,66 @@ }, { "data": { - "text/html": "\n
\n", - "text/plain": "alt.Chart(...)" + "text/html": [ + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.Chart(...)" + ] }, "metadata": {}, "output_type": "display_data" @@ -385,7 +630,7 @@ }, { "cell_type": "code", - "execution_count": 175, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -440,7 +685,7 @@ }, { "cell_type": "code", - "execution_count": 176, + "execution_count": 13, "metadata": {}, "outputs": [ { @@ -464,8 +709,66 @@ }, { "data": { - "text/html": "\n
\n", - "text/plain": "alt.LayerChart(...)" + "text/html": [ + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.LayerChart(...)" + ] }, "metadata": {}, "output_type": "display_data" @@ -494,7 +797,7 @@ }, { "cell_type": "code", - "execution_count": 177, + "execution_count": 14, "metadata": {}, "outputs": [ { @@ -540,7 +843,7 @@ }, { "cell_type": "code", - "execution_count": 178, + "execution_count": 15, "metadata": {}, "outputs": [ { @@ -561,8 +864,66 @@ }, { "data": { - "text/html": "\n
\n", - "text/plain": "alt.Chart(...)" + "text/html": [ + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.Chart(...)" + ] }, "metadata": {}, "output_type": "display_data" @@ -591,7 +952,7 @@ }, { "cell_type": "code", - "execution_count": 179, + "execution_count": 16, "metadata": {}, "outputs": [ { @@ -640,7 +1001,7 @@ }, { "cell_type": "code", - "execution_count": 180, + "execution_count": 17, "metadata": {}, "outputs": [ { @@ -662,8 +1023,66 @@ }, { "data": { - "text/html": "\n
\n", - "text/plain": "alt.Chart(...)" + "text/html": [ + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.Chart(...)" + ] }, "metadata": {}, "output_type": "display_data" @@ -697,7 +1116,7 @@ }, { "cell_type": "code", - "execution_count": 181, + "execution_count": 18, "metadata": {}, "outputs": [ { @@ -746,7 +1165,7 @@ }, { "cell_type": "code", - "execution_count": 182, + "execution_count": 19, "metadata": {}, "outputs": [ { @@ -766,8 +1185,66 @@ }, { "data": { - "text/html": "\n
\n", - "text/plain": "alt.Chart(...)" + "text/html": [ + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.Chart(...)" + ] }, "metadata": {}, "output_type": "display_data" @@ -791,7 +1268,7 @@ }, { "cell_type": "code", - "execution_count": 183, + "execution_count": 20, "metadata": {}, "outputs": [ { @@ -852,7 +1329,7 @@ }, { "cell_type": "code", - "execution_count": 184, + "execution_count": 21, "metadata": {}, "outputs": [ { @@ -875,8 +1352,66 @@ }, { "data": { - "text/html": "\n
\n", - "text/plain": "alt.Chart(...)" + "text/html": [ + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.Chart(...)" + ] }, "metadata": {}, "output_type": "display_data" @@ -894,7 +1429,7 @@ }, { "cell_type": "code", - "execution_count": 185, + "execution_count": 22, "metadata": {}, "outputs": [ { @@ -963,7 +1498,7 @@ }, { "cell_type": "code", - "execution_count": 186, + "execution_count": 23, "metadata": {}, "outputs": [ { @@ -986,8 +1521,66 @@ }, { "data": { - "text/html": "\n
\n", - "text/plain": "alt.Chart(...)" + "text/html": [ + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.Chart(...)" + ] }, "metadata": {}, "output_type": "display_data" @@ -1021,7 +1614,7 @@ }, { "cell_type": "code", - "execution_count": 187, + "execution_count": 24, "metadata": {}, "outputs": [ { @@ -1076,7 +1669,7 @@ }, { "cell_type": "code", - "execution_count": 188, + "execution_count": 25, "metadata": {}, "outputs": [ { @@ -1098,8 +1691,66 @@ }, { "data": { - "text/html": "\n
\n", - "text/plain": "alt.Chart(...)" + "text/html": [ + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.Chart(...)" + ] }, "metadata": {}, "output_type": "display_data" @@ -1129,7 +1780,7 @@ }, { "cell_type": "code", - "execution_count": 189, + "execution_count": 26, "metadata": {}, "outputs": [ { @@ -1193,7 +1844,7 @@ }, { "cell_type": "code", - "execution_count": 190, + "execution_count": 27, "metadata": {}, "outputs": [ { @@ -1217,8 +1868,66 @@ }, { "data": { - "text/html": "\n
\n", - "text/plain": "alt.Chart(...)" + "text/html": [ + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.Chart(...)" + ] }, "metadata": {}, "output_type": "display_data" @@ -1254,7 +1963,7 @@ }, { "cell_type": "code", - "execution_count": 191, + "execution_count": 28, "metadata": {}, "outputs": [ { @@ -1318,7 +2027,7 @@ }, { "cell_type": "code", - "execution_count": 192, + "execution_count": 29, "metadata": {}, "outputs": [ { @@ -1342,8 +2051,66 @@ }, { "data": { - "text/html": "\n
\n", - "text/plain": "alt.Chart(...)" + "text/html": [ + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.Chart(...)" + ] }, "metadata": {}, "output_type": "display_data" @@ -1386,7 +2153,7 @@ }, { "cell_type": "code", - "execution_count": 193, + "execution_count": 30, "metadata": {}, "outputs": [ { @@ -1434,7 +2201,7 @@ }, { "cell_type": "code", - "execution_count": 194, + "execution_count": 31, "metadata": {}, "outputs": [ { @@ -1456,8 +2223,66 @@ }, { "data": { - "text/html": "\n
\n", - "text/plain": "alt.LayerChart(...)" + "text/html": [ + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.LayerChart(...)" + ] }, "metadata": {}, "output_type": "display_data" @@ -1499,7 +2324,7 @@ }, { "cell_type": "code", - "execution_count": 195, + "execution_count": 32, "metadata": {}, "outputs": [ { @@ -1556,7 +2381,7 @@ }, { "cell_type": "code", - "execution_count": 196, + "execution_count": 33, "metadata": {}, "outputs": [ { @@ -1573,8 +2398,66 @@ }, { "data": { - "text/html": "\n
\n", - "text/plain": "alt.FacetChart(...)" + "text/html": [ + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.FacetChart(...)" + ] }, "metadata": {}, "output_type": "display_data" @@ -1599,7 +2482,7 @@ }, { "cell_type": "code", - "execution_count": 197, + "execution_count": 34, "metadata": {}, "outputs": [ { @@ -1657,7 +2540,7 @@ }, { "cell_type": "code", - "execution_count": 198, + "execution_count": 35, "metadata": {}, "outputs": [ { @@ -1680,8 +2563,66 @@ }, { "data": { - "text/html": "\n
\n", - "text/plain": "alt.FacetChart(...)" + "text/html": [ + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.FacetChart(...)" + ] }, "metadata": {}, "output_type": "display_data" @@ -1715,7 +2656,7 @@ }, { "cell_type": "code", - "execution_count": 199, + "execution_count": 36, "metadata": {}, "outputs": [ { @@ -1778,7 +2719,7 @@ }, { "cell_type": "code", - "execution_count": 200, + "execution_count": 37, "metadata": {}, "outputs": [ { @@ -1802,8 +2743,66 @@ }, { "data": { - "text/html": "\n
\n", - "text/plain": "alt.HConcatChart(...)" + "text/html": [ + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.HConcatChart(...)" + ] }, "metadata": {}, "output_type": "display_data" @@ -1839,7 +2838,7 @@ }, { "cell_type": "code", - "execution_count": 201, + "execution_count": 38, "metadata": {}, "outputs": [ { @@ -1900,7 +2899,7 @@ }, { "cell_type": "code", - "execution_count": 202, + "execution_count": 39, "metadata": {}, "outputs": [ { @@ -1922,8 +2921,66 @@ }, { "data": { - "text/html": "\n
\n", - "text/plain": "alt.HConcatChart(...)" + "text/html": [ + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.HConcatChart(...)" + ] }, "metadata": {}, "output_type": "display_data" @@ -1945,127 +3002,17 @@ "display_chart(chart)" ] }, - { - "cell_type": "code", - "execution_count": 203, - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Mapping, Generic, TypeVar\n", - "from abc import ABC, abstractmethod\n", - "\n", - "T = TypeVar(\"T\")\n", - "SpecProperty = str | int | float | bool | None | dict\n", - "\n", - "\n", - "class BaseRenderer(ABC, Generic[T]):\n", - " \"\"\"\n", - " Base class for all renderers.\n", - " \"\"\"\n", - "\n", - " def render(self, spec: Mapping) -> T:\n", - " \"\"\"\n", - " Render a dictionary-based specification\n", - " into a concrete rendering product of type `T`.\n", - " The rendering object's actual type depends on the concrete renderer.\n", - "\n", - " :param spec: dictionary-based specification\n", - " :return: product of the rendering\n", - " \"\"\"\n", - "\n", - " def visit_mapping(\n", - " dct: Mapping, path: tuple[str | int, ...] = (), acc: T = self._initial\n", - " ):\n", - " \"\"\"\n", - " Recursively visit a dictionary-based specification.\n", - "\n", - " :param dct: dictionary-based specification\n", - " :param path: path to the current node\n", - " :param acc: accumulated rendering product\n", - " \"\"\"\n", - " for key, value in dct.items():\n", - " if isinstance(value, dict):\n", - " # if the current value does not have further dicts in it, then call the visitor\n", - " if not any(isinstance(v, dict) for v in value.values()):\n", - " acc = self._visitor(value, path + (key,), acc)\n", - " else:\n", - " visit_mapping(value, path + (key,), acc)\n", - " elif isinstance(value, list):\n", - " for i, item in enumerate(value):\n", - " visit_mapping(item, path + (key, i), acc)\n", - " else:\n", - " acc = self._visitor(value, path + (key,), acc)\n", - "\n", - " return visit_mapping(spec)\n", - "\n", - " @property\n", - " @abstractmethod\n", - " def _initial(self) -> T:\n", - " raise NotImplementedError\n", - "\n", - " @abstractmethod\n", - " def _visitor(self, value: SpecProperty, path: tuple[str | int, ...], acc: T) -> T:\n", - " raise NotImplementedError\n", - "\n", - "\n", - "class VegaLiteRenderer(BaseRenderer):\n", - " @property\n", - " def _initial(self) -> T:\n", - " return {}\n", - "\n", - " def _visitor(self, value: SpecProperty, path: tuple[str | int, ...], acc: T) -> T:\n", - " print(path, value)\n", - " return acc" - ] - }, - { - "cell_type": "code", - "execution_count": 205, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'number_rows': 100, 'field': [{'name': 'temperature', 'type': 'number'}, {'name': 'condition', 'type': 'string'}], 'view': [{'mark': [{'type': 'tick', 'encoding': [{'channel': 'y', 'field': 'temperature'}]}]}, {'mark': [{'type': 'bar', 'encoding': [{'channel': 'y', 'field': 'temperature', 'aggregate': 'mean'}, {'channel': 'x', 'field': 'condition'}]}], 'scale': [{'channel': 'x', 'type': 'ordinal'}]}], 'scale': [{'channel': 'y', 'type': 'linear', 'zero': 'true'}]}\n", - "('number_rows',) 100\n", - "('field', 0, 'name') temperature\n", - "('field', 0, 'type') number\n", - "('field', 1, 'name') condition\n", - "('field', 1, 'type') string\n", - "('view', 0, 'mark', 0, 'type') tick\n", - "('view', 0, 'mark', 0, 'encoding', 0, 'channel') y\n", - "('view', 0, 'mark', 0, 'encoding', 0, 'field') temperature\n", - "('view', 1, 'mark', 0, 'type') bar\n", - "('view', 1, 'mark', 0, 'encoding', 0, 'channel') y\n", - "('view', 1, 'mark', 0, 'encoding', 0, 'field') temperature\n", - "('view', 1, 'mark', 0, 'encoding', 0, 'aggregate') mean\n", - "('view', 1, 'mark', 0, 'encoding', 1, 'channel') x\n", - "('view', 1, 'mark', 0, 'encoding', 1, 'field') condition\n", - "('view', 1, 'scale', 0, 'channel') x\n", - "('view', 1, 'scale', 0, 'type') ordinal\n", - "('scale', 0, 'channel') y\n", - "('scale', 0, 'type') linear\n", - "('scale', 0, 'zero') true\n" - ] - } - ], - "source": [ - "vl = VegaLiteRenderer()\n", - "print(spec)\n", - "vl.render(spec)" - ], - "metadata": { - "collapsed": false - } - }, { "cell_type": "code", "execution_count": null, - "outputs": [], - "source": [], "metadata": { - "collapsed": false - } + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "outputs": [], + "source": [] } ], "metadata": { @@ -2084,9 +3031,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.3" + "version": "3.10.0" } }, "nbformat": 4, - "nbformat_minor": 1 + "nbformat_minor": 4 } diff --git a/draco/renderer.py b/draco/renderer.py deleted file mode 100644 index dc98d9f5..00000000 --- a/draco/renderer.py +++ /dev/null @@ -1,155 +0,0 @@ -from abc import ABC, abstractmethod -from dataclasses import dataclass, field -from typing import Generic, Optional, TypeVar - -from draco.utils import dict_value_by_path - -T = TypeVar("T") -SpecProperty = str | int | float | bool | None | dict | list - - -@dataclass(frozen=True, kw_only=True) -class VisitedItem(Generic[T]): - value: SpecProperty - path: tuple[int | str, ...] - acc: T = field(repr=False) - spec: dict = field(repr=False) - - @property - def parent(self) -> Optional["VisitedItem"]: - has_parent = len(self.path) > 0 - if has_parent: - parent_path = self.path[:-1] - value = dict_value_by_path(self.spec, parent_path) - return VisitedItem( - value=value, path=parent_path, acc=self.acc, spec=self.spec - ) - return None - - -class BaseRenderer(ABC, Generic[T]): - """ - Base class for all renderers. - """ - - def render(self, spec: dict) -> T: - """ - Render a dictionary-based specification - into a concrete rendering product of type `T`. - The rendering object's actual type depends on the concrete renderer. - - :param spec: dictionary-based specification - :return: product of the rendering - """ - - def traverse(dct: dict, path: tuple[str | int, ...], acc: T): - """ - Recursively visit a dictionary-based specification. - - :param dct: dictionary-based specification - :param path: path to the current node - :param acc: accumulated rendering product - :return: the most recent rendering product - """ - has_complex_children = any( - isinstance(v, dict) or isinstance(v, list) for v in dct.values() - ) - if not has_complex_children: - return self._visitor( - VisitedItem(value=dct, path=path, acc=acc, spec=spec) - ) - - for key, value in dct.items(): - if isinstance(value, dict): - acc = traverse(value, path + (key,), acc) - elif isinstance(value, list): - for i, item in enumerate(value): - acc = traverse(item, path + (key, i), acc) - else: - acc = self._visitor( - VisitedItem(value=value, path=path + (key,), acc=acc, spec=spec) - ) - return acc - - return traverse(dct=spec, path=(), acc=self._initial) - - @property - @abstractmethod - def _initial(self) -> T: - """ - :return: The initial rendering product to start with. - """ - raise NotImplementedError - - @abstractmethod - def _visitor(self, item: VisitedItem[T]) -> T: - """ - The callback to be invoked for each visited item of the specification. - Should be implemented by concrete renderers to produce the rendering product - step-by-step based on the contents of the supplied `payload`. - - :param item: the visited item - :return: the updated rendering product - """ - raise NotImplementedError - - -class VegaLiteRenderer(BaseRenderer[dict]): - @property - def _initial(self) -> dict: - return {"x": 0} - - def _visitor(self, item: VisitedItem) -> dict: - print(item) - return {"x": item.acc["x"] + 1} - - -if __name__ == "__main__": - from draco.fact_utils import answer_set_to_dict - from draco.run import run_clingo - - def facts_to_dict(facts: list[str]): - result = run_clingo(facts) - return answer_set_to_dict(next(result).answer_set) - - facts = [ - "attribute(number_rows,root,100).", - "entity(field,root,temperature).", - "attribute((field,name),temperature,temperature).", - "attribute((field,type),temperature,number).", - "entity(field,root,condition).", - "attribute((field,name),condition,condition).", - "attribute((field,type),condition,string).", - "entity(view,root,0).", - "entity(mark,0,1).", - "attribute((mark,type),1,tick).", - "entity(encoding,1,2).", - "attribute((encoding,channel),2,y).", - "attribute((encoding,field),2,temperature).", - "entity(view,root,3).", - "entity(mark,3,4).", - "attribute((mark,type),4,bar).", - "entity(encoding,4,5).", - "attribute((encoding,channel),5,y).", - "attribute((encoding,field),5,temperature).", - "attribute((encoding,aggregate),5,mean).", - "entity(encoding,4,6).", - "attribute((encoding,channel),6,x).", - "attribute((encoding,field),6,condition).", - "entity(scale,3,7).", - "attribute((scale,channel),7,x).", - "attribute((scale,type),7,ordinal).", - "entity(scale,root,8).", - "attribute((scale,channel),8,y).", - "attribute((scale,type),8,linear).", - "attribute((scale,zero),8,true).", - ] - spec = facts_to_dict(facts) - from pprint import pprint - - pprint(spec) - print() - - vl = VegaLiteRenderer() - product = vl.render(dict(spec)) - print(product) diff --git a/draco/renderer/__init__.py b/draco/renderer/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/draco/renderer/base_renderer.py b/draco/renderer/base_renderer.py new file mode 100644 index 00000000..6426514d --- /dev/null +++ b/draco/renderer/base_renderer.py @@ -0,0 +1,150 @@ +from abc import ABC, abstractmethod +from dataclasses import dataclass, field +from functools import cached_property +from typing import Generic, Optional, TypeVar + +from pandas import DataFrame + +from draco.utils import dict_value_by_path + +T = TypeVar("T") +SpecProperty = str | int | float | bool | None | dict | list + + +@dataclass(frozen=True) +class _VisitedItemRaw(Generic[T]): + value: SpecProperty + path: tuple[int | str, ...] + acc: T = field(repr=False) + + +@dataclass(frozen=True) +class VisitedItem(Generic[T]): + item: _VisitedItemRaw[T] + spec: dict = field(repr=False) + + @property + def value(self) -> SpecProperty: + return self.item.value + + @property + def path(self) -> tuple[int | str, ...]: + return self.item.path + + @property + def acc(self) -> T: + return self.item.acc + + @property + def type(self) -> str: + is_list_element = isinstance(self.path[-1], int) + if is_list_element: + return self.path[-2] + return self.path[-1] + + @cached_property + def parent(self) -> Optional["VisitedItem"]: + raw_parent = self.__parent() + if raw_parent is not None: + return VisitedItem(item=raw_parent, spec=self.spec) + return None + + def __parent(self) -> _VisitedItemRaw | None: + has_parent = len(self.path) > 1 + if has_parent: + parent_path = self.path[:-1] + parent_value = dict_value_by_path(self.spec, parent_path) + return _VisitedItemRaw(parent_value, parent_path, self.acc) + return None + + +class BaseRenderer(ABC, Generic[T]): + """ + Base class for all renderers. + """ + + def __init__(self, spec: dict, df: DataFrame): + """ + Creates a new renderer for the specified specification and data frame. + + :param spec: dictionary-based specification + :param df: data frame to be rendered + """ + self.spec = spec + self.df = df + + def build(self) -> T: + """ + Builds a concrete rendering product of type `T` from `self.spec` and `self.df`. + The rendering object's actual type depends on the concrete renderer. + :return: product of the rendering + """ + + def traverse(dct: dict, path: tuple[str | int, ...], acc: T): + """ + Recursively visit a dictionary-based specification. + + :param dct: dictionary-based specification + :param path: path to the current node + :param acc: accumulated rendering product + :return: the most recent rendering product + """ + has_complex_children = any( + isinstance(v, dict) or isinstance(v, list) for v in dct.values() + ) + if not has_complex_children: + return self._visitor( + VisitedItem( + item=_VisitedItemRaw(value=dct, path=path, acc=acc), + spec=self.spec, + ) + ) + + for key, value in dct.items(): + if isinstance(value, dict): + acc = traverse(value, path + (key,), acc) + elif isinstance(value, list): + for i, item in enumerate(value): + acc = traverse(item, path + (key, i), acc) + else: + acc = self._visitor( + VisitedItem( + item=_VisitedItemRaw( + value=value, path=path + (key,), acc=acc + ), + spec=self.spec, + ) + ) + return acc + + product = traverse(dct=self.spec, path=(), acc=self._initial) + post_processed = self.post_build_hook(product) + return post_processed + + @property + @abstractmethod + def _initial(self) -> T: + """ + :return: The initial rendering product to start with. + """ + raise NotImplementedError + + @abstractmethod + def _visitor(self, item: VisitedItem[T]) -> T: + """ + The callback to be invoked for each visited item of the specification. + Should be implemented by concrete renderers to produce the rendering product + step-by-step based on the contents of the supplied `payload`. + + :param item: the visited item + :return: the updated rendering product + """ + raise NotImplementedError + + def post_build_hook(self, product: T) -> T: + """ + Called after the traversal of the specification is completed. + Acts as a hook for post-processing the rendering product. + :return: the updated rendering product + """ + return product diff --git a/draco/renderer/vega_lite.py b/draco/renderer/vega_lite.py new file mode 100644 index 00000000..e69de29b diff --git a/draco/renderer/vega_lite_renderer.py b/draco/renderer/vega_lite_renderer.py new file mode 100644 index 00000000..b95873d0 --- /dev/null +++ b/draco/renderer/vega_lite_renderer.py @@ -0,0 +1,75 @@ +import json + +from pandas import DataFrame + +from .base_renderer import BaseRenderer, VisitedItem + + +class VegaLiteRenderer(BaseRenderer[dict]): + def __init__(self, spec: dict, df: DataFrame): + super().__init__(spec, df) + + @property + def _initial(self) -> dict: + return { + "$schema": "https://vega.github.io/schema/vega-lite/v5.2.0.json", + } + + def _visitor(self, item: VisitedItem) -> dict: + match item.type: + case "mark": + pass + case "encoding": + pass + case "scale": + pass + return item.acc + + def post_build_hook(self, product: dict) -> dict: + # add data to VL spec + data = self.df.to_dict(orient="records") + product["data"] = {"values": data} + return product + + __DATA_TYPE_MAP__ = { + "number": "quantitative", + "string": "nominal", + } + + +if __name__ == "__main__": + from pprint import pprint + + from draco.fact_utils import answer_set_to_dict + from draco.run import run_clingo + + def facts_to_dict(facts: list[str]): + result = run_clingo(facts) + return answer_set_to_dict(next(result).answer_set) + + facts = [ + "attribute(number_rows,root,100).", + "entity(field,root,temperature).", + "attribute((field,name),temperature,temperature).", + "attribute((field,type),temperature,number).", + "entity(view,root,0).", + "entity(mark,0,1).", + "attribute((mark,type),1,tick).", + "entity(encoding,1,2).", + "attribute((encoding,channel),2,x).", + "attribute((encoding,field),2,temperature).", + "entity(scale,0,3).", + "attribute((scale,channel),3,x).", + "attribute((scale,type),3,linear).", + ] + spec = facts_to_dict(facts) + + pprint(spec) + print() + + df = DataFrame.from_records( + data=[dict(a=i, b=25 * i, c=50 * i) for i in range(1, 11)] + ) + vl = VegaLiteRenderer(dict(spec), df) + product = vl.build() + print(json.dumps(product, indent=2)) From 535dcb4683af0a861aa00331f6daedd9d341d79b Mon Sep 17 00:00:00 2001 From: Dominik Moritz Date: Tue, 8 Nov 2022 08:03:55 -0800 Subject: [PATCH 04/45] ci: set up python before installing stuff --- .github/workflows/codeql.yml | 15 ++++++++++----- .github/workflows/test.yml | 12 ++++++++---- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f41e46e5..f98c686e 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,4 +1,4 @@ -name: "CodeQL" +name: CodeQL on: push: @@ -19,17 +19,21 @@ jobs: strategy: fail-fast: false - matrix: - language: [ python ] steps: - name: Checkout uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version-file: ".python-version" + cache: "poetry" + - name: Initialize CodeQL uses: github/codeql-action/init@v2 with: - languages: ${{ matrix.language }} + languages: python queries: +security-and-quality - name: Autobuild @@ -38,4 +42,5 @@ jobs: - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 with: - category: "/language:${{ matrix.language }}" + setup-python-dependencies: false + category: "/language:python" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f7a45fca..7570b192 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,11 +14,13 @@ jobs: - uses: actions/checkout@v3 - name: Install poetry run: pipx install poetry - - uses: actions/setup-python@v4 + - name: Set up Python + uses: actions/setup-python@v4 with: python-version-file: ".python-version" cache: "poetry" - - run: poetry install + - name: Install dependencies + run: poetry install - name: Run tests run: poetry run pytest --cov=./ --cov-report=xml draco @@ -39,7 +41,8 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 + - name: Set up Python + uses: actions/setup-python@v4 with: python-version-file: ".python-version" - uses: psf/black@stable @@ -58,7 +61,8 @@ jobs: contents: write steps: - - uses: fastify/github-action-merge-dependabot@v3.4.2 + - name: Merge pull requests + uses: fastify/github-action-merge-dependabot@v3.4.2 with: github-token: ${{ secrets.GITHUB_TOKEN }} target: minor From 6f3306309e19089495db42f5da15becc6fcd28a7 Mon Sep 17 00:00:00 2001 From: Dominik Moritz Date: Tue, 8 Nov 2022 08:09:31 -0800 Subject: [PATCH 05/45] rm poetry --- .github/workflows/codeql.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f98c686e..716fed52 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -28,7 +28,6 @@ jobs: uses: actions/setup-python@v4 with: python-version-file: ".python-version" - cache: "poetry" - name: Initialize CodeQL uses: github/codeql-action/init@v2 From 01e2eba284e5b7d3a827bc0c293bd42c4bb562c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Thu, 10 Nov 2022 12:53:12 +0100 Subject: [PATCH 06/45] feat: `AltairRenderer` stable impl Renders all the example charts --- docs/facts/examples-vl.ipynb | 3039 -------------------------- draco/renderer/altair_renderer.py | 173 ++ draco/renderer/base_renderer.py | 142 +- draco/renderer/vega_lite.py | 0 draco/renderer/vega_lite_renderer.py | 75 - draco/types.py | 229 +- 6 files changed, 408 insertions(+), 3250 deletions(-) delete mode 100644 docs/facts/examples-vl.ipynb create mode 100644 draco/renderer/altair_renderer.py delete mode 100644 draco/renderer/vega_lite.py delete mode 100644 draco/renderer/vega_lite_renderer.py diff --git a/docs/facts/examples-vl.ipynb b/docs/facts/examples-vl.ipynb deleted file mode 100644 index 81532108..00000000 --- a/docs/facts/examples-vl.ipynb +++ /dev/null @@ -1,3039 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Example Charts\n", - "\n", - "This notebook recreates the examples from [https://dig.cmu.edu/draco2/facts/examples.html#](https://dig.cmu.edu/draco2/facts/examples.html#)." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from pprint import pprint\n", - "from draco.fact_utils import answer_set_to_dict\n", - "from draco.run import run_clingo\n", - "import altair as alt\n", - "from altair import datum" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "def facts_to_dict(facts: list[str]):\n", - " result = run_clingo(facts)\n", - " return answer_set_to_dict(next(result).answer_set)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "from IPython.display import display\n", - "import json\n", - "\n", - "\n", - "def display_chart(chart: alt.Chart):\n", - " dct = json.loads(chart.to_json())\n", - " dct.pop(\"data\")\n", - " dct.pop(\"datasets\")\n", - " pprint(dct)\n", - " display(chart)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "import random\n", - "\n", - "# Generate a random dataframe with the following columns:\n", - "# - temperature: a random float between -10 and 44\n", - "# - wind: a random float between 0 and 100\n", - "# - precipitation: a random float between 0 and 100\n", - "# - condition: a random string from the list [\"drizzle\", \"fog\", \"rain\", \"sun\", \"snow\"]\n", - "NUM_ROWS = 100\n", - "df = pd.DataFrame(\n", - " {\n", - " \"temperature\": [random.uniform(-10, 44) for _ in range(NUM_ROWS)],\n", - " \"wind\": [random.uniform(0, 100) for _ in range(NUM_ROWS)],\n", - " \"precipitation\": [random.uniform(0, 100) for _ in range(NUM_ROWS)],\n", - " \"condition\": [\n", - " random.choice([\"drizzle\", \"fog\", \"rain\", \"sun\", \"snow\"])\n", - " for _ in range(NUM_ROWS)\n", - " ],\n", - " }\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
temperaturewindprecipitationcondition
017.89365378.75685641.611246rain
15.62281825.42199974.905551rain
223.3902099.84610381.335364rain
320.88955427.53521327.654932drizzle
433.91026297.91032836.534943snow
\n", - "
" - ], - "text/plain": [ - " temperature wind precipitation condition\n", - "0 17.893653 78.756856 41.611246 rain\n", - "1 5.622818 25.421999 74.905551 rain\n", - "2 23.390209 9.846103 81.335364 rain\n", - "3 20.889554 27.535213 27.654932 drizzle\n", - "4 33.910262 97.910328 36.534943 snow" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Single View, Single Mark Charts" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Tick Plot" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'field': [{'name': 'temperature', 'type': 'number'}],\n", - " 'number_rows': 100,\n", - " 'view': [{'mark': [{'encoding': [{'channel': 'x', 'field': 'temperature'}],\n", - " 'type': 'tick'}],\n", - " 'scale': [{'channel': 'x', 'type': 'linear'}]}]}\n" - ] - } - ], - "source": [ - "facts = [\n", - " \"attribute(number_rows,root,100).\",\n", - " \"entity(field,root,temperature).\",\n", - " \"attribute((field,name),temperature,temperature).\",\n", - " \"attribute((field,type),temperature,number).\",\n", - " \"entity(view,root,0).\",\n", - " \"entity(mark,0,1).\",\n", - " \"attribute((mark,type),1,tick).\",\n", - " \"entity(encoding,1,2).\",\n", - " \"attribute((encoding,channel),2,x).\",\n", - " \"attribute((encoding,field),2,temperature).\",\n", - " \"entity(scale,0,3).\",\n", - " \"attribute((scale,channel),3,x).\",\n", - " \"attribute((scale,type),3,linear).\",\n", - "]\n", - "spec = facts_to_dict(facts)\n", - "pprint(spec)" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", - " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", - " 'encoding': {'x': {'field': 'temperature',\n", - " 'scale': {'type': 'linear'},\n", - " 'type': 'quantitative'}},\n", - " 'mark': 'tick'}\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/petergy/Library/Caches/pypoetry/virtualenvs/draco-q9RTEhXP-py3.10/lib/python3.10/site-packages/altair/utils/core.py:317: FutureWarning: iteritems is deprecated and will be removed in a future version. Use .items instead.\n", - " for col_name, dtype in df.dtypes.iteritems():\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.Chart(...)" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "base = alt.Chart(df)\n", - "tick = base.mark_tick().encode(\n", - " x=alt.X(field=\"temperature\", type=\"quantitative\", scale=alt.Scale(type=\"linear\"))\n", - ")\n", - "display_chart(tick)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Tick Plot with a Log Scale" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'field': [{'name': 'temperature', 'type': 'number'}],\n", - " 'number_rows': 100,\n", - " 'view': [{'mark': [{'encoding': [{'channel': 'x', 'field': 'temperature'}],\n", - " 'type': 'tick'}],\n", - " 'scale': [{'channel': 'x', 'type': 'log'}]}]}\n" - ] - } - ], - "source": [ - "facts = [\n", - " \"attribute(number_rows,root,100).\",\n", - " \"entity(field,root,temperature).\",\n", - " \"attribute((field,name),temperature,temperature).\",\n", - " \"attribute((field,type),temperature,number).\",\n", - " \"entity(view,root,0).\",\n", - " \"entity(mark,0,1).\",\n", - " \"attribute((mark,type),1,tick).\",\n", - " \"entity(encoding,1,2).\",\n", - " \"attribute((encoding,channel),2,x).\",\n", - " \"attribute((encoding,field),2,temperature).\",\n", - " \"entity(scale,0,3).\",\n", - " \"attribute((scale,channel),3,x).\",\n", - " \"attribute((scale,type),3,log).\",\n", - "]\n", - "spec = facts_to_dict(facts)\n", - "pprint(spec)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", - " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", - " 'encoding': {'x': {'field': 'temperature',\n", - " 'scale': {'type': 'log'},\n", - " 'type': 'quantitative'}},\n", - " 'mark': 'tick',\n", - " 'transform': [{'filter': '(datum.temperature > 0)'}]}\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.Chart(...)" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "base = alt.Chart(df).transform_filter(datum.temperature > 0)\n", - "tick = base.mark_tick().encode(\n", - " x=alt.X(field=\"temperature\", type=\"quantitative\", scale=alt.Scale(type=\"log\"))\n", - ")\n", - "display_chart(tick)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Bar Chart" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'field': [{'name': 'temperature', 'type': 'number'},\n", - " {'name': 'condition', 'type': 'string'}],\n", - " 'number_rows': 100,\n", - " 'view': [{'coordinates': 'cartesian',\n", - " 'mark': [{'encoding': [{'channel': 'x', 'field': 'condition'},\n", - " {'aggregate': 'mean',\n", - " 'channel': 'y',\n", - " 'field': 'temperature'}],\n", - " 'type': 'bar'}],\n", - " 'scale': [{'channel': 'x', 'type': 'ordinal'},\n", - " {'channel': 'y', 'type': 'linear', 'zero': 'true'}]}]}\n" - ] - } - ], - "source": [ - "facts = [\n", - " \"attribute(number_rows,root,100).\",\n", - " \"entity(field,root,temperature).\",\n", - " \"attribute((field,name),temperature,temperature).\",\n", - " \"attribute((field,type),temperature,number).\",\n", - " \"entity(field,root,condition).\",\n", - " \"attribute((field,name),condition,condition).\",\n", - " \"attribute((field,type),condition,string).\",\n", - " \"entity(view,root,0).\",\n", - " \"attribute((view,coordinates),0,cartesian).\",\n", - " \"entity(mark,0,1).\",\n", - " \"attribute((mark,type),1,bar).\",\n", - " \"entity(encoding,1,2).\",\n", - " \"attribute((encoding,channel),2,x).\",\n", - " \"attribute((encoding,field),2,condition).\",\n", - " \"entity(encoding,1,3).\",\n", - " \"attribute((encoding,channel),3,y).\",\n", - " \"attribute((encoding,field),3,temperature).\",\n", - " \"attribute((encoding,aggregate),3,mean).\",\n", - " \"entity(scale,0,4).\",\n", - " \"attribute((scale,channel),4,x).\",\n", - " \"attribute((scale,type),4,ordinal).\",\n", - " \"entity(scale,0,5).\",\n", - " \"attribute((scale,channel),5,y).\",\n", - " \"attribute((scale,type),5,linear).\",\n", - " \"attribute((scale,zero),5,true).\",\n", - "]\n", - "spec = facts_to_dict(facts)\n", - "pprint(spec)" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", - " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", - " 'encoding': {'x': {'field': 'condition',\n", - " 'scale': {'type': 'ordinal'},\n", - " 'type': 'nominal'},\n", - " 'y': {'aggregate': 'mean',\n", - " 'field': 'temperature',\n", - " 'scale': {'type': 'linear', 'zero': True},\n", - " 'type': 'quantitative'}},\n", - " 'mark': 'bar'}\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.Chart(...)" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "base = alt.Chart(df)\n", - "bar = base.mark_bar().encode(\n", - " x=alt.X(field=\"condition\", type=\"nominal\", scale=alt.Scale(type=\"ordinal\")),\n", - " y=alt.Y(\n", - " field=\"temperature\",\n", - " type=\"quantitative\",\n", - " aggregate=\"mean\",\n", - " scale=alt.Scale(type=\"linear\", zero=True),\n", - " ),\n", - ")\n", - "display_chart(bar)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Radial Chart" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'field': [{'name': 'temperature', 'type': 'number'},\n", - " {'name': 'condition', 'type': 'string'}],\n", - " 'number_rows': 100,\n", - " 'view': [{'coordinates': 'polar',\n", - " 'mark': [{'encoding': [{'channel': 'x', 'field': 'condition'},\n", - " {'aggregate': 'mean',\n", - " 'channel': 'y',\n", - " 'field': 'temperature'}],\n", - " 'type': 'bar'}],\n", - " 'scale': [{'channel': 'x', 'type': 'ordinal'},\n", - " {'channel': 'y', 'type': 'linear', 'zero': 'true'}]}]}\n" - ] - } - ], - "source": [ - "facts = [\n", - " \"attribute(number_rows,root,100).\",\n", - " \"entity(field,root,temperature).\",\n", - " \"attribute((field,name),temperature,temperature).\",\n", - " \"attribute((field,type),temperature,number).\",\n", - " \"entity(field,root,condition).\",\n", - " \"attribute((field,name),condition,condition).\",\n", - " \"attribute((field,type),condition,string).\",\n", - " \"entity(view,root,0).\",\n", - " \"attribute((view,coordinates),0,polar).\",\n", - " \"entity(mark,0,1).\",\n", - " \"attribute((mark,type),1,bar).\",\n", - " \"entity(encoding,1,2).\",\n", - " \"attribute((encoding,channel),2,x).\",\n", - " \"attribute((encoding,field),2,condition).\",\n", - " \"entity(encoding,1,3).\",\n", - " \"attribute((encoding,channel),3,y).\",\n", - " \"attribute((encoding,field),3,temperature).\",\n", - " \"attribute((encoding,aggregate),3,mean).\",\n", - " \"entity(scale,0,4).\",\n", - " \"attribute((scale,channel),4,x).\",\n", - " \"attribute((scale,type),4,ordinal).\",\n", - " \"entity(scale,0,5).\",\n", - " \"attribute((scale,channel),5,y).\",\n", - " \"attribute((scale,type),5,linear).\",\n", - " \"attribute((scale,zero),5,true).\",\n", - "]\n", - "spec = facts_to_dict(facts)\n", - "pprint(spec)" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", - " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", - " 'layer': [{'encoding': {'radius': {'aggregate': 'mean',\n", - " 'field': 'temperature',\n", - " 'type': 'quantitative'},\n", - " 'theta': {'field': 'condition', 'type': 'nominal'}},\n", - " 'mark': {'stroke': '#ffffff', 'type': 'arc'}},\n", - " {'encoding': {'radius': {'aggregate': 'mean',\n", - " 'field': 'temperature',\n", - " 'type': 'quantitative'},\n", - " 'text': {'field': 'condition', 'type': 'nominal'},\n", - " 'theta': {'field': 'condition', 'type': 'nominal'}},\n", - " 'mark': {'radiusOffset': 15, 'type': 'text'}}]}\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.LayerChart(...)" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "base = alt.Chart(df)\n", - "arc = base.mark_arc(stroke=\"#ffffff\").encode(\n", - " theta=alt.Theta(field=\"condition\", type=\"nominal\"),\n", - " radius=alt.Radius(field=\"temperature\", type=\"quantitative\", aggregate=\"mean\"),\n", - ")\n", - "text = base.mark_text(radiusOffset=15).encode(\n", - " theta=alt.Theta(field=\"condition\", type=\"nominal\"),\n", - " radius=alt.Radius(field=\"temperature\", type=\"quantitative\", aggregate=\"mean\"),\n", - " text=alt.Text(field=\"condition\", type=\"nominal\"),\n", - ")\n", - "display_chart(arc + text)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Histogram" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'field': [{'name': 'condition', 'type': 'string'}],\n", - " 'number_rows': 100,\n", - " 'view': [{'mark': [{'encoding': [{'channel': 'x', 'field': 'condition'},\n", - " {'aggregate': 'count', 'channel': 'y'}],\n", - " 'type': 'bar'}],\n", - " 'scale': [{'channel': 'x', 'type': 'ordinal'},\n", - " {'channel': 'y', 'type': 'linear', 'zero': 'true'}]}]}\n" - ] - } - ], - "source": [ - "facts = [\n", - " \"attribute(number_rows,root,100).\",\n", - " \"entity(field,root,condition).\",\n", - " \"attribute((field,name),condition,condition).\",\n", - " \"attribute((field,type),condition,string).\",\n", - " \"entity(view,root,0).\",\n", - " \"entity(mark,0,1).\",\n", - " \"attribute((mark,type),1,bar).\",\n", - " \"entity(encoding,1,2).\",\n", - " \"attribute((encoding,channel),2,x).\",\n", - " \"attribute((encoding,field),2,condition).\",\n", - " \"entity(encoding,1,3).\",\n", - " \"attribute((encoding,channel),3,y).\",\n", - " \"attribute((encoding,aggregate),3,count).\",\n", - " \"entity(scale,0,4).\",\n", - " \"attribute((scale,channel),4,x).\",\n", - " \"attribute((scale,type),4,ordinal).\",\n", - " \"entity(scale,0,5).\",\n", - " \"attribute((scale,channel),5,y).\",\n", - " \"attribute((scale,type),5,linear).\",\n", - " \"attribute((scale,zero),5,true).\",\n", - "]\n", - "spec = facts_to_dict(facts)\n", - "pprint(spec)" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", - " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", - " 'encoding': {'x': {'field': 'condition',\n", - " 'scale': {'type': 'ordinal'},\n", - " 'type': 'nominal'},\n", - " 'y': {'aggregate': 'count',\n", - " 'field': 'condition',\n", - " 'scale': {'type': 'linear', 'zero': True},\n", - " 'type': 'nominal'}},\n", - " 'mark': 'bar'}\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.Chart(...)" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "base = alt.Chart(df)\n", - "bar = base.mark_bar().encode(\n", - " x=alt.X(field=\"condition\", type=\"nominal\", scale=alt.Scale(type=\"ordinal\")),\n", - " y=alt.Y(\n", - " field=\"condition\",\n", - " type=\"nominal\",\n", - " aggregate=\"count\",\n", - " scale=alt.Scale(type=\"linear\", zero=True),\n", - " ),\n", - ")\n", - "display_chart(bar)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Binned Histrogram" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'field': [{'name': 'temperature', 'type': 'number'}],\n", - " 'number_rows': 100,\n", - " 'view': [{'mark': [{'encoding': [{'binning': 10,\n", - " 'channel': 'x',\n", - " 'field': 'temperature'},\n", - " {'aggregate': 'count', 'channel': 'y'}],\n", - " 'type': 'bar'}],\n", - " 'scale': [{'channel': 'x', 'type': 'linear'},\n", - " {'channel': 'y', 'type': 'linear', 'zero': 'true'}]}]}\n" - ] - } - ], - "source": [ - "facts = [\n", - " \"attribute(number_rows,root,100).\",\n", - " \"entity(field,root,temperature).\",\n", - " \"attribute((field,name),temperature,temperature).\",\n", - " \"attribute((field,type),temperature,number).\",\n", - " \"entity(view,root,0).\",\n", - " \"entity(mark,0,1).\",\n", - " \"attribute((mark,type),1,bar).\",\n", - " \"entity(encoding,1,2).\",\n", - " \"attribute((encoding,channel),2,x).\",\n", - " \"attribute((encoding,field),2,temperature).\",\n", - " \"attribute((encoding,binning),2,10).\",\n", - " \"entity(encoding,1,3).\",\n", - " \"attribute((encoding,channel),3,y).\",\n", - " \"attribute((encoding,aggregate),3,count).\",\n", - " \"entity(scale,0,4).\",\n", - " \"attribute((scale,channel),4,x).\",\n", - " \"attribute((scale,type),4,linear).\",\n", - " \"entity(scale,0,5).\",\n", - " \"attribute((scale,channel),5,y).\",\n", - " \"attribute((scale,type),5,linear).\",\n", - " \"attribute((scale,zero),5,true).\",\n", - "]\n", - "spec = facts_to_dict(facts)\n", - "pprint(spec)" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", - " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", - " 'encoding': {'x': {'bin': {'maxbins': 10},\n", - " 'field': 'temperature',\n", - " 'scale': {'type': 'linear'},\n", - " 'type': 'quantitative'},\n", - " 'y': {'aggregate': 'count',\n", - " 'field': 'temperature',\n", - " 'scale': {'type': 'linear', 'zero': True},\n", - " 'type': 'quantitative'}},\n", - " 'mark': 'bar'}\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.Chart(...)" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "base = alt.Chart(df)\n", - "bar = base.mark_bar().encode(\n", - " x=alt.X(\n", - " field=\"temperature\",\n", - " type=\"quantitative\",\n", - " bin=alt.Bin(maxbins=10),\n", - " scale=alt.Scale(type=\"linear\"),\n", - " ),\n", - " y=alt.Y(\n", - " field=\"temperature\",\n", - " type=\"quantitative\",\n", - " aggregate=\"count\",\n", - " scale=alt.Scale(type=\"linear\", zero=True),\n", - " ),\n", - ")\n", - "display_chart(bar)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Scatterplot" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'field': [{'name': 'temperature', 'type': 'number'},\n", - " {'name': 'wind', 'type': 'number'}],\n", - " 'number_rows': 100,\n", - " 'view': [{'mark': [{'encoding': [{'channel': 'x', 'field': 'temperature'},\n", - " {'channel': 'y', 'field': 'wind'}],\n", - " 'type': 'point'}],\n", - " 'scale': [{'channel': 'x', 'type': 'linear'},\n", - " {'channel': 'y', 'type': 'linear'}]}]}\n" - ] - } - ], - "source": [ - "facts = [\n", - " \"attribute(number_rows,root,100).\",\n", - " \"entity(field,root,temperature).\",\n", - " \"attribute((field,name),temperature,temperature).\",\n", - " \"attribute((field,type),temperature,number).\",\n", - " \"entity(field,root,wind).\",\n", - " \"attribute((field,name),wind,wind).\",\n", - " \"attribute((field,type),wind,number).\",\n", - " \"entity(view,root,0).\",\n", - " \"entity(mark,0,1).\",\n", - " \"attribute((mark,type),1,point).\",\n", - " \"entity(encoding,1,2).\",\n", - " \"attribute((encoding,channel),2,x).\",\n", - " \"attribute((encoding,field),2,temperature).\",\n", - " \"entity(encoding,1,3).\",\n", - " \"attribute((encoding,channel),3,y).\",\n", - " \"attribute((encoding,field),3,wind).\",\n", - " \"entity(scale,0,4).\",\n", - " \"attribute((scale,channel),4,x).\",\n", - " \"attribute((scale,type),4,linear).\",\n", - " \"entity(scale,0,5).\",\n", - " \"attribute((scale,channel),5,y).\",\n", - " \"attribute((scale,type),5,linear).\",\n", - "]\n", - "spec = facts_to_dict(facts)\n", - "pprint(spec)" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", - " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", - " 'encoding': {'x': {'field': 'temperature',\n", - " 'scale': {'type': 'linear'},\n", - " 'type': 'quantitative'},\n", - " 'y': {'field': 'wind',\n", - " 'scale': {'type': 'linear'},\n", - " 'type': 'quantitative'}},\n", - " 'mark': 'point'}\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.Chart(...)" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "base = alt.Chart(df)\n", - "point = base.mark_point().encode(\n", - " x=alt.X(field=\"temperature\", type=\"quantitative\", scale=alt.Scale(type=\"linear\")),\n", - " y=alt.Y(field=\"wind\", type=\"quantitative\", scale=alt.Scale(type=\"linear\")),\n", - ")\n", - "display_chart(point)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Scatterplot with Color" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'field': [{'name': 'temperature', 'type': 'number'},\n", - " {'name': 'wind', 'type': 'number'},\n", - " {'name': 'condition', 'type': 'string'}],\n", - " 'number_rows': 100,\n", - " 'view': [{'mark': [{'encoding': [{'channel': 'x', 'field': 'temperature'},\n", - " {'channel': 'y', 'field': 'wind'},\n", - " {'channel': 'color', 'field': 'condition'}],\n", - " 'type': 'point'}],\n", - " 'scale': [{'channel': 'x', 'type': 'linear'},\n", - " {'channel': 'y', 'type': 'linear'},\n", - " {'channel': 'color', 'type': 'categorical'}]}]}\n" - ] - } - ], - "source": [ - "facts = [\n", - " \"attribute(number_rows,root,100).\",\n", - " \"entity(field,root,temperature).\",\n", - " \"attribute((field,name),temperature,temperature).\",\n", - " \"attribute((field,type),temperature,number).\",\n", - " \"entity(field,root,wind).\",\n", - " \"attribute((field,name),wind,wind).\",\n", - " \"attribute((field,type),wind,number).\",\n", - " \"entity(field,root,condition).\",\n", - " \"attribute((field,name),condition,condition).\",\n", - " \"attribute((field,type),condition,string).\",\n", - " \"entity(view,root,0).\",\n", - " \"entity(mark,0,1).\",\n", - " \"attribute((mark,type),1,point).\",\n", - " \"entity(encoding,1,2).\",\n", - " \"attribute((encoding,channel),2,x).\",\n", - " \"attribute((encoding,field),2,temperature).\",\n", - " \"entity(encoding,1,3).\",\n", - " \"attribute((encoding,channel),3,y).\",\n", - " \"attribute((encoding,field),3,wind).\",\n", - " \"entity(encoding,1,4).\",\n", - " \"attribute((encoding,channel),4,color).\",\n", - " \"attribute((encoding,field),4,condition).\",\n", - " \"entity(scale,0,5).\",\n", - " \"attribute((scale,channel),5,x).\",\n", - " \"attribute((scale,type),5,linear).\",\n", - " \"entity(scale,0,6).\",\n", - " \"attribute((scale,channel),6,y).\",\n", - " \"attribute((scale,type),6,linear).\",\n", - " \"entity(scale,0,7).\",\n", - " \"attribute((scale,channel),7,color).\",\n", - " \"attribute((scale,type),7,categorical).\",\n", - "]\n", - "spec = facts_to_dict(facts)\n", - "pprint(spec)" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", - " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", - " 'encoding': {'color': {'field': 'condition',\n", - " 'scale': {'type': 'ordinal'},\n", - " 'type': 'nominal'},\n", - " 'x': {'field': 'temperature',\n", - " 'scale': {'type': 'linear'},\n", - " 'type': 'quantitative'},\n", - " 'y': {'field': 'wind',\n", - " 'scale': {'type': 'linear'},\n", - " 'type': 'quantitative'}},\n", - " 'mark': 'point'}\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.Chart(...)" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "base = alt.Chart(df)\n", - "point = base.mark_point().encode(\n", - " x=alt.X(field=\"temperature\", type=\"quantitative\", scale=alt.Scale(type=\"linear\")),\n", - " y=alt.Y(field=\"wind\", type=\"quantitative\", scale=alt.Scale(type=\"linear\")),\n", - " color=alt.Color(field=\"condition\", type=\"nominal\", scale=alt.Scale(type=\"ordinal\")),\n", - ")\n", - "display_chart(point)" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'field': [{'name': 'temperature', 'type': 'number'},\n", - " {'name': 'wind', 'type': 'number'},\n", - " {'name': 'precipitation', 'type': 'number'}],\n", - " 'number_rows': 100,\n", - " 'view': [{'mark': [{'encoding': [{'channel': 'x', 'field': 'temperature'},\n", - " {'channel': 'y', 'field': 'wind'},\n", - " {'channel': 'size',\n", - " 'field': 'precipitation'}],\n", - " 'type': 'point'}],\n", - " 'scale': [{'channel': 'x', 'type': 'linear'},\n", - " {'channel': 'y', 'type': 'linear'},\n", - " {'channel': 'size', 'type': 'linear'}]}]}\n" - ] - } - ], - "source": [ - "facts = [\n", - " \"attribute(number_rows,root,100).\",\n", - " \"entity(field,root,temperature).\",\n", - " \"attribute((field,name),temperature,temperature).\",\n", - " \"attribute((field,type),temperature,number).\",\n", - " \"entity(field,root,wind).\",\n", - " \"attribute((field,name),wind,wind).\",\n", - " \"attribute((field,type),wind,number).\",\n", - " \"entity(field,root,precipitation).\",\n", - " \"attribute((field,name),precipitation,precipitation).\",\n", - " \"attribute((field,type),precipitation,number).\",\n", - " \"entity(view,root,0).\",\n", - " \"entity(mark,0,1).\",\n", - " \"attribute((mark,type),1,point).\",\n", - " \"entity(encoding,1,2).\",\n", - " \"attribute((encoding,channel),2,x).\",\n", - " \"attribute((encoding,field),2,temperature).\",\n", - " \"entity(encoding,1,3).\",\n", - " \"attribute((encoding,channel),3,y).\",\n", - " \"attribute((encoding,field),3,wind).\",\n", - " \"entity(encoding,1,4).\",\n", - " \"attribute((encoding,channel),4,size).\",\n", - " \"attribute((encoding,field),4,precipitation).\",\n", - " \"entity(scale,0,5).\",\n", - " \"attribute((scale,channel),5,x).\",\n", - " \"attribute((scale,type),5,linear).\",\n", - " \"entity(scale,0,6).\",\n", - " \"attribute((scale,channel),6,y).\",\n", - " \"attribute((scale,type),6,linear).\",\n", - " \"entity(scale,0,7).\",\n", - " \"attribute((scale,channel),7,size).\",\n", - " \"attribute((scale,type),7,linear).\",\n", - "]\n", - "spec = facts_to_dict(facts)\n", - "pprint(spec)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Bubble Chart" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", - " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", - " 'encoding': {'size': {'field': 'precipitation',\n", - " 'scale': {'type': 'linear'},\n", - " 'type': 'quantitative'},\n", - " 'x': {'field': 'temperature',\n", - " 'scale': {'type': 'linear'},\n", - " 'type': 'quantitative'},\n", - " 'y': {'field': 'wind',\n", - " 'scale': {'type': 'linear'},\n", - " 'type': 'quantitative'}},\n", - " 'mark': 'point'}\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.Chart(...)" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "base = alt.Chart(df)\n", - "point = base.mark_point().encode(\n", - " x=alt.X(field=\"temperature\", type=\"quantitative\", scale=alt.Scale(type=\"linear\")),\n", - " y=alt.Y(field=\"wind\", type=\"quantitative\", scale=alt.Scale(type=\"linear\")),\n", - " size=alt.Size(\n", - " field=\"precipitation\", type=\"quantitative\", scale=alt.Scale(type=\"linear\")\n", - " ),\n", - ")\n", - "display_chart(point)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Stacked Charts" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Pie Chart" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'field': [{'name': 'temperature', 'type': 'number'},\n", - " {'name': 'condition', 'type': 'string'}],\n", - " 'number_rows': 100,\n", - " 'view': [{'coordinates': 'polar',\n", - " 'mark': [{'encoding': [{'aggregate': 'count',\n", - " 'channel': 'y',\n", - " 'stack': 'zero'},\n", - " {'channel': 'color', 'field': 'condition'}],\n", - " 'type': 'bar'}],\n", - " 'scale': [{'channel': 'y', 'type': 'linear', 'zero': 'true'},\n", - " {'channel': 'color', 'type': 'categorical'}]}]}\n" - ] - } - ], - "source": [ - "facts = [\n", - " \"attribute(number_rows,root,100).\",\n", - " \"entity(field,root,temperature).\",\n", - " \"attribute((field,name),temperature,temperature).\",\n", - " \"attribute((field,type),temperature,number).\",\n", - " \"entity(field,root,condition).\",\n", - " \"attribute((field,name),condition,condition).\",\n", - " \"attribute((field,type),condition,string).\",\n", - " \"entity(view,root,0).\",\n", - " \"attribute((view,coordinates),0,polar).\",\n", - " \"entity(mark,0,1).\",\n", - " \"attribute((mark,type),1,bar).\",\n", - " \"entity(encoding,1,2).\",\n", - " \"attribute((encoding,channel),2,y).\",\n", - " \"attribute((encoding,aggregate),2,count).\",\n", - " \"attribute((encoding,stack),2,zero).\",\n", - " \"entity(encoding,1,3).\",\n", - " \"attribute((encoding,channel),3,color).\",\n", - " \"attribute((encoding,field),3,condition).\",\n", - " \"entity(scale,0,4).\",\n", - " \"attribute((scale,channel),4,y).\",\n", - " \"attribute((scale,type),4,linear).\",\n", - " \"attribute((scale,zero),4,true).\",\n", - " \"entity(scale,0,5).\",\n", - " \"attribute((scale,channel),5,color).\",\n", - " \"attribute((scale,type),5,categorical).\",\n", - "]\n", - "spec = facts_to_dict(facts)\n", - "pprint(spec)" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", - " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", - " 'encoding': {'color': {'field': 'condition',\n", - " 'scale': {'type': 'ordinal'},\n", - " 'type': 'nominal'},\n", - " 'theta': {'aggregate': 'count',\n", - " 'field': 'temperature',\n", - " 'scale': {'type': 'linear', 'zero': True},\n", - " 'stack': 'zero',\n", - " 'type': 'quantitative'}},\n", - " 'mark': 'arc'}\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.Chart(...)" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "base = alt.Chart(df)\n", - "arc = base.mark_arc().encode(\n", - " theta=alt.Theta(\n", - " field=\"temperature\",\n", - " type=\"quantitative\",\n", - " aggregate=\"count\",\n", - " stack=\"zero\",\n", - " scale=alt.Scale(type=\"linear\", zero=True),\n", - " ),\n", - " color=alt.Color(field=\"condition\", type=\"nominal\", scale=alt.Scale(type=\"ordinal\")),\n", - ")\n", - "display_chart(arc)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Stacked Bar Chart" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'field': [{'name': 'temperature', 'type': 'number'},\n", - " {'name': 'condition', 'type': 'string'}],\n", - " 'number_rows': 100,\n", - " 'view': [{'mark': [{'encoding': [{'binning': 10,\n", - " 'channel': 'x',\n", - " 'field': 'temperature'},\n", - " {'aggregate': 'count',\n", - " 'channel': 'y',\n", - " 'stack': 'zero'},\n", - " {'channel': 'color', 'field': 'condition'}],\n", - " 'type': 'bar'}],\n", - " 'scale': [{'channel': 'x', 'type': 'linear'},\n", - " {'channel': 'y', 'type': 'linear', 'zero': 'true'},\n", - " {'channel': 'color', 'type': 'categorical'}]}]}\n" - ] - } - ], - "source": [ - "facts = [\n", - " \"attribute(number_rows,root,100).\",\n", - " \"entity(field,root,temperature).\",\n", - " \"attribute((field,name),temperature,temperature).\",\n", - " \"attribute((field,type),temperature,number).\",\n", - " \"entity(field,root,condition).\",\n", - " \"attribute((field,name),condition,condition).\",\n", - " \"attribute((field,type),condition,string).\",\n", - " \"entity(view,root,0).\",\n", - " \"entity(mark,0,1).\",\n", - " \"attribute((mark,type),1,bar).\",\n", - " \"entity(encoding,1,2).\",\n", - " \"attribute((encoding,channel),2,x).\",\n", - " \"attribute((encoding,field),2,temperature).\",\n", - " \"attribute((encoding,binning),2,10).\",\n", - " \"entity(encoding,1,3).\",\n", - " \"attribute((encoding,channel),3,y).\",\n", - " \"attribute((encoding,aggregate),3,count).\",\n", - " \"attribute((encoding,stack),3,zero).\",\n", - " \"entity(encoding,1,4).\",\n", - " \"attribute((encoding,channel),4,color).\",\n", - " \"attribute((encoding,field),4,condition).\",\n", - " \"entity(scale,0,5).\",\n", - " \"attribute((scale,channel),5,x).\",\n", - " \"attribute((scale,type),5,linear).\",\n", - " \"entity(scale,0,6).\",\n", - " \"attribute((scale,channel),6,y).\",\n", - " \"attribute((scale,type),6,linear).\",\n", - " \"attribute((scale,zero),6,true).\",\n", - " \"entity(scale,0,7).\",\n", - " \"attribute((scale,channel),7,color).\",\n", - " \"attribute((scale,type),7,categorical).\",\n", - "]\n", - "spec = facts_to_dict(facts)\n", - "pprint(spec)" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", - " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", - " 'encoding': {'color': {'field': 'condition', 'type': 'nominal'},\n", - " 'x': {'bin': {'maxbins': 10},\n", - " 'field': 'temperature',\n", - " 'scale': {'type': 'linear'},\n", - " 'type': 'quantitative'},\n", - " 'y': {'aggregate': 'count',\n", - " 'field': 'temperature',\n", - " 'scale': {'type': 'linear', 'zero': True},\n", - " 'stack': 'zero',\n", - " 'type': 'quantitative'}},\n", - " 'mark': 'bar'}\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.Chart(...)" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "base = alt.Chart(df)\n", - "bar = base.mark_bar().encode(\n", - " x=alt.X(\n", - " field=\"temperature\",\n", - " type=\"quantitative\",\n", - " bin=alt.Bin(maxbins=10),\n", - " scale=alt.Scale(type=\"linear\"),\n", - " ),\n", - " y=alt.Y(\n", - " field=\"temperature\",\n", - " type=\"quantitative\",\n", - " aggregate=\"count\",\n", - " stack=\"zero\",\n", - " scale=alt.Scale(type=\"linear\", zero=True),\n", - " ),\n", - " color=alt.Color(field=\"condition\", type=\"nominal\"),\n", - ")\n", - "display_chart(bar)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Normalized (Percentage) Stacked Bar Chart" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'field': [{'name': 'temperature', 'type': 'number'},\n", - " {'name': 'condition', 'type': 'string'}],\n", - " 'number_rows': 100,\n", - " 'view': [{'mark': [{'encoding': [{'aggregate': 'count',\n", - " 'channel': 'x',\n", - " 'stack': 'normalize'},\n", - " {'binning': 10,\n", - " 'channel': 'y',\n", - " 'field': 'temperature'},\n", - " {'channel': 'color', 'field': 'condition'}],\n", - " 'type': 'bar'}],\n", - " 'scale': [{'channel': 'x', 'type': 'linear', 'zero': 'true'},\n", - " {'channel': 'y', 'type': 'linear'},\n", - " {'channel': 'color', 'type': 'categorical'}]}]}\n" - ] - } - ], - "source": [ - "facts = [\n", - " \"attribute(number_rows,root,100).\",\n", - " \"entity(field,root,temperature).\",\n", - " \"attribute((field,name),temperature,temperature).\",\n", - " \"attribute((field,type),temperature,number).\",\n", - " \"entity(field,root,condition).\",\n", - " \"attribute((field,name),condition,condition).\",\n", - " \"attribute((field,type),condition,string).\",\n", - " \"entity(view,root,0).\",\n", - " \"entity(mark,0,1).\",\n", - " \"attribute((mark,type),1,bar).\",\n", - " \"entity(encoding,1,2).\",\n", - " \"attribute((encoding,channel),2,x).\",\n", - " \"attribute((encoding,aggregate),2,count).\",\n", - " \"attribute((encoding,stack),2,normalize).\",\n", - " \"entity(encoding,1,3).\",\n", - " \"attribute((encoding,channel),3,y).\",\n", - " \"attribute((encoding,field),3,temperature).\",\n", - " \"attribute((encoding,binning),3,10).\",\n", - " \"entity(encoding,1,4).\",\n", - " \"attribute((encoding,channel),4,color).\",\n", - " \"attribute((encoding,field),4,condition).\",\n", - " \"entity(scale,0,5).\",\n", - " \"attribute((scale,channel),5,x).\",\n", - " \"attribute((scale,type),5,linear).\",\n", - " \"attribute((scale,zero),5,true).\",\n", - " \"entity(scale,0,6).\",\n", - " \"attribute((scale,channel),6,y).\",\n", - " \"attribute((scale,type),6,linear).\",\n", - " \"entity(scale,0,7).\",\n", - " \"attribute((scale,channel),7,color).\",\n", - " \"attribute((scale,type),7,categorical).\",\n", - "]\n", - "spec = facts_to_dict(facts)\n", - "pprint(spec)" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", - " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", - " 'encoding': {'color': {'field': 'condition', 'type': 'nominal'},\n", - " 'x': {'aggregate': 'count',\n", - " 'field': 'temperature',\n", - " 'scale': {'type': 'linear', 'zero': True},\n", - " 'stack': 'normalize',\n", - " 'type': 'quantitative'},\n", - " 'y': {'bin': {'maxbins': 10},\n", - " 'field': 'temperature',\n", - " 'scale': {'type': 'linear'},\n", - " 'type': 'quantitative'}},\n", - " 'mark': 'bar'}\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.Chart(...)" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "base = alt.Chart(df)\n", - "bar = base.mark_bar().encode(\n", - " x=alt.X(\n", - " field=\"temperature\",\n", - " type=\"quantitative\",\n", - " aggregate=\"count\",\n", - " stack=\"normalize\",\n", - " scale=alt.Scale(type=\"linear\", zero=True),\n", - " ),\n", - " y=alt.Y(\n", - " field=\"temperature\",\n", - " type=\"quantitative\",\n", - " bin=alt.Bin(maxbins=10),\n", - " scale=alt.Scale(type=\"linear\"),\n", - " ),\n", - " color=alt.Color(field=\"condition\", type=\"nominal\"),\n", - ")\n", - "display_chart(bar)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Multi Mark (Layered) Charts" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Bar with a Tick" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'field': [{'name': 'temperature', 'type': 'number'}],\n", - " 'number_rows': 100,\n", - " 'view': [{'mark': [{'encoding': [{'aggregate': 'mean',\n", - " 'channel': 'x',\n", - " 'field': 'temperature'}],\n", - " 'type': 'bar'},\n", - " {'encoding': [{'channel': 'x', 'field': 'temperature'}],\n", - " 'type': 'tick'}],\n", - " 'scale': [{'channel': 'x', 'type': 'linear', 'zero': 'true'}]}]}\n" - ] - } - ], - "source": [ - "facts = [\n", - " \"attribute(number_rows,root,100).\",\n", - " \"entity(field,root,temperature).\",\n", - " \"attribute((field,name),temperature,temperature).\",\n", - " \"attribute((field,type),temperature,number).\",\n", - " \"entity(view,root,0).\",\n", - " \"entity(mark,0,1).\",\n", - " \"attribute((mark,type),1,bar).\",\n", - " \"entity(encoding,1,2).\",\n", - " \"attribute((encoding,channel),2,x).\",\n", - " \"attribute((encoding,aggregate),2,mean).\",\n", - " \"attribute((encoding,field),2,temperature).\",\n", - " \"entity(mark,0,3).\",\n", - " \"attribute((mark,type),3,tick).\",\n", - " \"entity(encoding,3,4).\",\n", - " \"attribute((encoding,channel),4,x).\",\n", - " \"attribute((encoding,field),4,temperature).\",\n", - " \"entity(scale,0,5).\",\n", - " \"attribute((scale,channel),5,x).\",\n", - " \"attribute((scale,type),5,linear).\",\n", - " \"attribute((scale,zero),5,true).\",\n", - "]\n", - "spec = facts_to_dict(facts)\n", - "pprint(spec)" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", - " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", - " 'layer': [{'encoding': {'x': {'aggregate': 'mean',\n", - " 'field': 'temperature',\n", - " 'scale': {'type': 'linear', 'zero': True},\n", - " 'type': 'quantitative'}},\n", - " 'mark': 'bar'},\n", - " {'encoding': {'x': {'field': 'temperature',\n", - " 'scale': {'type': 'linear', 'zero': True},\n", - " 'type': 'quantitative'}},\n", - " 'mark': 'tick'}]}\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.LayerChart(...)" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "base = alt.Chart(df)\n", - "bar = base.mark_bar().encode(\n", - " x=alt.X(\n", - " field=\"temperature\",\n", - " type=\"quantitative\",\n", - " aggregate=\"mean\",\n", - " scale=alt.Scale(type=\"linear\", zero=True),\n", - " ),\n", - ")\n", - "tick = base.mark_tick().encode(\n", - " x=alt.X(\n", - " field=\"temperature\",\n", - " type=\"quantitative\",\n", - " scale=alt.Scale(type=\"linear\", zero=True),\n", - " ),\n", - ")\n", - "display_chart(bar + tick)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Facets" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Facet Scatterplot into Columns" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'field': [{'name': 'temperature', 'type': 'number'},\n", - " {'name': 'wind', 'type': 'number'},\n", - " {'name': 'condition', 'type': 'string'}],\n", - " 'number_rows': 100,\n", - " 'view': [{'facet': [{'channel': 'col', 'field': 'condition'}],\n", - " 'mark': [{'encoding': [{'channel': 'x', 'field': 'temperature'},\n", - " {'channel': 'y', 'field': 'wind'}],\n", - " 'type': 'point'}],\n", - " 'scale': [{'channel': 'x', 'type': 'linear'},\n", - " {'channel': 'y', 'type': 'linear'}]}]}\n" - ] - } - ], - "source": [ - "facts = [\n", - " \"attribute(number_rows,root,100).\",\n", - " \"entity(field,root,temperature).\",\n", - " \"attribute((field,name),temperature,temperature).\",\n", - " \"attribute((field,type),temperature,number).\",\n", - " \"entity(field,root,wind).\",\n", - " \"attribute((field,name),wind,wind).\",\n", - " \"attribute((field,type),wind,number).\",\n", - " \"entity(field,root,condition).\",\n", - " \"attribute((field,name),condition,condition).\",\n", - " \"attribute((field,type),condition,string).\",\n", - " \"entity(view,root,0).\",\n", - " \"entity(mark,0,1).\",\n", - " \"attribute((mark,type),1,point).\",\n", - " \"entity(encoding,1,2).\",\n", - " \"attribute((encoding,channel),2,x).\",\n", - " \"attribute((encoding,field),2,temperature).\",\n", - " \"entity(encoding,1,3).\",\n", - " \"attribute((encoding,channel),3,y).\",\n", - " \"attribute((encoding,field),3,wind).\",\n", - " \"entity(scale,0,4).\",\n", - " \"attribute((scale,channel),4,x).\",\n", - " \"attribute((scale,type),4,linear).\",\n", - " \"entity(scale,0,5).\",\n", - " \"attribute((scale,channel),5,y).\",\n", - " \"attribute((scale,type),5,linear).\",\n", - " \"entity(facet,0,6).\",\n", - " \"attribute((facet,channel),6,col).\",\n", - " \"attribute((facet,field),6,condition).\",\n", - "]\n", - "spec = facts_to_dict(facts)\n", - "pprint(spec)" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", - " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", - " 'facet': {'column': {'field': 'condition', 'type': 'nominal'}},\n", - " 'spec': {'encoding': {'x': {'field': 'temperature', 'type': 'quantitative'},\n", - " 'y': {'field': 'wind', 'type': 'quantitative'}},\n", - " 'mark': 'point'}}\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.FacetChart(...)" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "base = alt.Chart(df)\n", - "point = base.mark_point().encode(\n", - " x=alt.X(field=\"temperature\", type=\"quantitative\"),\n", - " y=alt.Y(field=\"wind\", type=\"quantitative\"),\n", - ")\n", - "facet = point.facet(column=alt.Column(field=\"condition\", type=\"nominal\"))\n", - "display_chart(facet)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Facet Scatterplot by Binned Data into Columns" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'field': [{'name': 'temperature', 'type': 'number'},\n", - " {'name': 'wind', 'type': 'number'},\n", - " {'name': 'condition', 'type': 'string'}],\n", - " 'number_rows': 100,\n", - " 'view': [{'facet': [{'binning': 10, 'channel': 'col', 'field': 'temperature'}],\n", - " 'mark': [{'encoding': [{'channel': 'x', 'field': 'condition'},\n", - " {'channel': 'y', 'field': 'wind'}],\n", - " 'type': 'point'}],\n", - " 'scale': [{'channel': 'x', 'type': 'ordinal'},\n", - " {'channel': 'y', 'type': 'linear'}]}]}\n" - ] - } - ], - "source": [ - "facts = [\n", - " \"attribute(number_rows,root,100).\",\n", - " \"entity(field,root,temperature).\",\n", - " \"attribute((field,name),temperature,temperature).\",\n", - " \"attribute((field,type),temperature,number).\",\n", - " \"entity(field,root,wind).\",\n", - " \"attribute((field,name),wind,wind).\",\n", - " \"attribute((field,type),wind,number).\",\n", - " \"entity(field,root,condition).\",\n", - " \"attribute((field,name),condition,condition).\",\n", - " \"attribute((field,type),condition,string).\",\n", - " \"entity(view,root,0).\",\n", - " \"entity(mark,0,1).\",\n", - " \"attribute((mark,type),1,point).\",\n", - " \"entity(encoding,1,2).\",\n", - " \"attribute((encoding,channel),2,x).\",\n", - " \"attribute((encoding,field),2,condition).\",\n", - " \"entity(encoding,1,3).\",\n", - " \"attribute((encoding,channel),3,y).\",\n", - " \"attribute((encoding,field),3,wind).\",\n", - " \"entity(scale,0,4).\",\n", - " \"attribute((scale,channel),4,x).\",\n", - " \"attribute((scale,type),4,ordinal).\",\n", - " \"entity(scale,0,5).\",\n", - " \"attribute((scale,channel),5,y).\",\n", - " \"attribute((scale,type),5,linear).\",\n", - " \"entity(facet,0,6).\",\n", - " \"attribute((facet,channel),6,col).\",\n", - " \"attribute((facet,field),6,temperature).\",\n", - " \"attribute((facet,binning),6,10).\",\n", - "]\n", - "spec = facts_to_dict(facts)\n", - "pprint(spec)" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", - " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", - " 'facet': {'column': {'bin': {'maxbins': 10},\n", - " 'field': 'temperature',\n", - " 'type': 'quantitative'}},\n", - " 'spec': {'encoding': {'x': {'field': 'condition',\n", - " 'scale': {'type': 'ordinal'},\n", - " 'type': 'nominal'},\n", - " 'y': {'field': 'wind',\n", - " 'scale': {'type': 'linear'},\n", - " 'type': 'quantitative'}},\n", - " 'mark': 'point'}}\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.FacetChart(...)" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "base = alt.Chart(df)\n", - "point = base.mark_point().encode(\n", - " x=alt.X(field=\"condition\", type=\"nominal\", scale=alt.Scale(type=\"ordinal\")),\n", - " y=alt.Y(field=\"wind\", type=\"quantitative\", scale=alt.Scale(type=\"linear\")),\n", - ")\n", - "facet = point.facet(\n", - " column=alt.Column(field=\"temperature\", type=\"quantitative\", bin=alt.Bin(maxbins=10))\n", - ")\n", - "display_chart(facet)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Multiple Views" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Tick Plot and Histogram" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'field': [{'name': 'temperature', 'type': 'number'},\n", - " {'name': 'condition', 'type': 'string'}],\n", - " 'number_rows': 100,\n", - " 'view': [{'mark': [{'encoding': [{'channel': 'y', 'field': 'temperature'}],\n", - " 'type': 'tick'}],\n", - " 'scale': [{'channel': 'y', 'type': 'linear', 'zero': 'true'}]},\n", - " {'mark': [{'encoding': [{'channel': 'x', 'field': 'condition'},\n", - " {'aggregate': 'count', 'channel': 'y'}],\n", - " 'type': 'bar'}],\n", - " 'scale': [{'channel': 'x', 'type': 'ordinal'},\n", - " {'channel': 'y', 'type': 'linear', 'zero': 'true'}]}]}\n" - ] - } - ], - "source": [ - "facts = [\n", - " \"attribute(number_rows,root,100).\",\n", - " \"entity(field,root,temperature).\",\n", - " \"attribute((field,name),temperature,temperature).\",\n", - " \"attribute((field,type),temperature,number).\",\n", - " \"entity(field,root,condition).\",\n", - " \"attribute((field,name),condition,condition).\",\n", - " \"attribute((field,type),condition,string).\",\n", - " \"entity(view,root,0).\",\n", - " \"entity(mark,0,1).\",\n", - " \"attribute((mark,type),1,tick).\",\n", - " \"entity(encoding,1,2).\",\n", - " \"attribute((encoding,channel),2,y).\",\n", - " \"attribute((encoding,field),2,temperature).\",\n", - " \"entity(scale,0,3).\",\n", - " \"attribute((scale,channel),3,y).\",\n", - " \"attribute((scale,type),3,linear).\",\n", - " \"attribute((scale,zero),3,true).\",\n", - " \"entity(view,root,4).\",\n", - " \"entity(mark,4,5).\",\n", - " \"attribute((mark,type),5,bar).\",\n", - " \"entity(encoding,5,6).\",\n", - " \"attribute((encoding,channel),6,x).\",\n", - " \"attribute((encoding,field),6,condition).\",\n", - " \"entity(encoding,5,7).\",\n", - " \"attribute((encoding,channel),7,y).\",\n", - " \"attribute((encoding,aggregate),7,count).\",\n", - " \"entity(scale,4,8).\",\n", - " \"attribute((scale,channel),8,x).\",\n", - " \"attribute((scale,type),8,ordinal).\",\n", - " \"entity(scale,4,9).\",\n", - " \"attribute((scale,channel),9,y).\",\n", - " \"attribute((scale,type),9,linear).\",\n", - " \"attribute((scale,zero),9,true).\",\n", - "]\n", - "spec = facts_to_dict(facts)\n", - "pprint(spec)" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", - " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", - " 'hconcat': [{'encoding': {'y': {'field': 'temperature',\n", - " 'scale': {'type': 'linear', 'zero': True},\n", - " 'type': 'quantitative'}},\n", - " 'mark': 'tick'},\n", - " {'encoding': {'x': {'field': 'condition',\n", - " 'scale': {'type': 'ordinal'},\n", - " 'type': 'nominal'},\n", - " 'y': {'aggregate': 'count',\n", - " 'field': 'condition',\n", - " 'type': 'nominal'}},\n", - " 'mark': 'bar'}]}\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.HConcatChart(...)" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "base = alt.Chart(df)\n", - "\n", - "tick = base.mark_tick().encode(\n", - " y=alt.Y(\n", - " field=\"temperature\",\n", - " type=\"quantitative\",\n", - " scale=alt.Scale(type=\"linear\", zero=True),\n", - " )\n", - ")\n", - "view_1 = tick\n", - "\n", - "bar = base.mark_bar().encode(\n", - " x=alt.X(field=\"condition\", type=\"nominal\", scale=alt.Scale(type=\"ordinal\")),\n", - " y=alt.Y(field=\"condition\", type=\"nominal\", aggregate=\"count\"),\n", - ")\n", - "view_2 = bar\n", - "\n", - "display_chart(view_1 | view_2)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Tick Plot and Histogram with Shared Y-Scale" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'field': [{'name': 'temperature', 'type': 'number'},\n", - " {'name': 'condition', 'type': 'string'}],\n", - " 'number_rows': 100,\n", - " 'scale': [{'channel': 'y', 'type': 'linear', 'zero': 'true'}],\n", - " 'view': [{'mark': [{'encoding': [{'channel': 'y', 'field': 'temperature'}],\n", - " 'type': 'tick'}]},\n", - " {'mark': [{'encoding': [{'aggregate': 'mean',\n", - " 'channel': 'y',\n", - " 'field': 'temperature'},\n", - " {'channel': 'x', 'field': 'condition'}],\n", - " 'type': 'bar'}],\n", - " 'scale': [{'channel': 'x', 'type': 'ordinal'}]}]}\n" - ] - } - ], - "source": [ - "facts = [\n", - " \"attribute(number_rows,root,100).\",\n", - " \"entity(field,root,temperature).\",\n", - " \"attribute((field,name),temperature,temperature).\",\n", - " \"attribute((field,type),temperature,number).\",\n", - " \"entity(field,root,condition).\",\n", - " \"attribute((field,name),condition,condition).\",\n", - " \"attribute((field,type),condition,string).\",\n", - " \"entity(view,root,0).\",\n", - " \"entity(mark,0,1).\",\n", - " \"attribute((mark,type),1,tick).\",\n", - " \"entity(encoding,1,2).\",\n", - " \"attribute((encoding,channel),2,y).\",\n", - " \"attribute((encoding,field),2,temperature).\",\n", - " \"entity(view,root,3).\",\n", - " \"entity(mark,3,4).\",\n", - " \"attribute((mark,type),4,bar).\",\n", - " \"entity(encoding,4,5).\",\n", - " \"attribute((encoding,channel),5,y).\",\n", - " \"attribute((encoding,field),5,temperature).\",\n", - " \"attribute((encoding,aggregate),5,mean).\",\n", - " \"entity(encoding,4,6).\",\n", - " \"attribute((encoding,channel),6,x).\",\n", - " \"attribute((encoding,field),6,condition).\",\n", - " \"entity(scale,3,7).\",\n", - " \"attribute((scale,channel),7,x).\",\n", - " \"attribute((scale,type),7,ordinal).\",\n", - " \"entity(scale,root,8).\",\n", - " \"attribute((scale,channel),8,y).\",\n", - " \"attribute((scale,type),8,linear).\",\n", - " \"attribute((scale,zero),8,true).\",\n", - "]\n", - "spec = facts_to_dict(facts)\n", - "pprint(spec)" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'$schema': 'https://vega.github.io/schema/vega-lite/v4.17.0.json',\n", - " 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},\n", - " 'hconcat': [{'encoding': {'y': {'field': 'temperature',\n", - " 'type': 'quantitative'}},\n", - " 'mark': 'tick'},\n", - " {'encoding': {'x': {'field': 'condition', 'type': 'nominal'},\n", - " 'y': {'aggregate': 'mean',\n", - " 'field': 'temperature',\n", - " 'type': 'quantitative'}},\n", - " 'mark': 'bar'}],\n", - " 'resolve': {'scale': {'y': 'shared'}}}\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.HConcatChart(...)" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "base = alt.Chart(df)\n", - "\n", - "tick = base.mark_tick().encode(y=alt.Y(field=\"temperature\", type=\"quantitative\"))\n", - "view_1 = tick\n", - "\n", - "bar = base.mark_bar().encode(\n", - " x=alt.X(field=\"condition\", type=\"nominal\"),\n", - " y=alt.Y(field=\"temperature\", type=\"quantitative\", aggregate=\"mean\"),\n", - ")\n", - "view_2 = bar\n", - "chart = alt.hconcat(view_1, view_2).resolve_scale(y=\"shared\")\n", - "\n", - "display_chart(chart)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false, - "jupyter": { - "outputs_hidden": false - } - }, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.0" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/draco/renderer/altair_renderer.py b/draco/renderer/altair_renderer.py new file mode 100644 index 00000000..e97f686c --- /dev/null +++ b/draco/renderer/altair_renderer.py @@ -0,0 +1,173 @@ +from dataclasses import dataclass +from typing import TypeVar + +import altair as alt +from pandas import DataFrame + +from ..types import ( + Encoding, + EncodingChannel, + Field, + FieldName, + Mark, + SpecificationDict, + View, +) +from .base_renderer import BaseRenderer + +VegaLiteChart = TypeVar("VegaLiteChart", alt.VConcatChart, alt.HConcatChart, alt.Chart) + + +@dataclass(frozen=True) +class VisitorContext: + spec: SpecificationDict + product: VegaLiteChart + views: list[View] | None = None + view: View | None = None + mark: Mark | None = None + encoding: Encoding | None = None + + +class AltairRenderer(BaseRenderer[VegaLiteChart]): + def build(self, spec: SpecificationDict, data: DataFrame) -> VegaLiteChart: + chart = alt.Chart(data) + views = [] + for v in spec.view: + for m in v.mark: + chart = self.__visit_mark( + ctx=VisitorContext( + spec=spec, product=chart, views=views, view=v, mark=m + ) + ) + for e in m.encoding: + chart = self.__visit_encoding( + ctx=VisitorContext( + spec=spec, + product=chart, + views=views, + view=v, + mark=m, + encoding=e, + ) + ) + chart = self.__visit_view( + ctx=VisitorContext(spec=spec, product=chart, views=views, view=v) + ) + views.append(chart) + return self.__visit_root( + ctx=VisitorContext(spec=spec, product=chart, views=views) + ) + + def display(self, product: VegaLiteChart) -> None: + pass + + def __visit_root(self, ctx: VisitorContext) -> VegaLiteChart: + views = ctx.views + chart = len(views) > 1 and alt.vconcat(*views) or views[0] + has_shared_scale = ctx.spec.scale is not None + if has_shared_scale: + channels = [s.channel for s in ctx.spec.scale] + resolve_scale_args = {c: "shared" for c in channels} + chart = chart.resolve_scale(**resolve_scale_args) + return chart + + def __visit_view(self, ctx: VisitorContext) -> VegaLiteChart: + view, chart = (ctx.view, ctx.product) + if view.facet is not None: + for f in view.facet: + channel = f.channel + facet_args = { + "field": f.field, + "type": self.__get_field_type(ctx.spec.field, f.field), + } + if f.binning is not None: + facet_args["bin"] = alt.BinParams(maxbins=f.binning) + match channel: + case "row": + chart = chart.facet(row=alt.Row(**facet_args)) + case "col": + chart = chart.facet(column=alt.Column(**facet_args)) + case _: + raise ValueError(f"Unknown facet channel: {channel}") + return chart + + def __visit_mark(self, ctx: VisitorContext) -> VegaLiteChart: + chart, mark_type = (ctx.product, ctx.mark.type) + match mark_type: + case "point": + return chart.mark_point() + case "bar": + return chart.mark_bar() + case "line": + return chart.mark_line() + case "area": + return chart.mark_area() + case "text": + return chart.mark_text() + case "tick": + return chart.mark_tick() + case "rect": + return chart.mark_rect() + case _: + raise ValueError(f"Unknown mark type: {mark_type}") + + def __visit_encoding(self, ctx: VisitorContext) -> VegaLiteChart: + spec, chart, view, encoding = (ctx.spec, ctx.product, ctx.view, ctx.encoding) + + custom_args = {} + if encoding.field is not None: + custom_args["field"] = encoding.field + custom_args["type"] = self.__get_field_type(spec.field, encoding.field) + if encoding.binning is not None: + custom_args["bin"] = alt.BinParams(maxbins=encoding.binning) + + if view.scale is not None: + scale_or_none = self.__get_scale_for_encoding(encoding.channel, view) + if scale_or_none is not None: + custom_args["scale"] = scale_or_none + + encoding_args = ( + encoding.dict(exclude_none=True, exclude={"channel", "field", "binning"}) + | custom_args + ) + + match encoding.channel: + case "x": + return chart.encode(x=alt.X(**encoding_args)) + case "y": + return chart.encode(y=alt.Y(**encoding_args)) + case "color": + return chart.encode(color=alt.Color(**encoding_args)) + case "size": + return chart.encode(size=alt.Size(**encoding_args)) + case "shape": + return chart.encode(shape=alt.Shape(**encoding_args)) + case "text": + return chart.encode(text=alt.Text(**encoding_args)) + case _: + raise ValueError(f"Unknown channel: {encoding.channel}") + + def __get_field_type(self, fields: list[Field], field_name: FieldName) -> str: + renames = { + "number": "quantitative", + "string": "nominal", + "boolean": "nominal", + "datetime": "temporal", + } + field_by_name = [f for f in fields if f.name == field_name] + if len(field_by_name) == 0: + raise ValueError(f"Unknown field: {field_name}") + return renames[field_by_name[0].type] + + def __get_scale_for_encoding( + self, channel: EncodingChannel, view: View + ) -> alt.Scale | None: + renames = { + "categorical": "ordinal", + } + for scale in view.scale: + if scale.channel == channel: + scale_args = scale.dict(exclude_none=True, exclude={"channel"}) + scale_args["type"] = renames.get(scale.type, scale.type) + return alt.Scale(**scale_args) + return None diff --git a/draco/renderer/base_renderer.py b/draco/renderer/base_renderer.py index 6426514d..e6550b8b 100644 --- a/draco/renderer/base_renderer.py +++ b/draco/renderer/base_renderer.py @@ -1,150 +1,22 @@ from abc import ABC, abstractmethod -from dataclasses import dataclass, field -from functools import cached_property -from typing import Generic, Optional, TypeVar +from typing import Generic, TypeVar from pandas import DataFrame -from draco.utils import dict_value_by_path +from ..types import SpecificationDict T = TypeVar("T") -SpecProperty = str | int | float | bool | None | dict | list - - -@dataclass(frozen=True) -class _VisitedItemRaw(Generic[T]): - value: SpecProperty - path: tuple[int | str, ...] - acc: T = field(repr=False) - - -@dataclass(frozen=True) -class VisitedItem(Generic[T]): - item: _VisitedItemRaw[T] - spec: dict = field(repr=False) - - @property - def value(self) -> SpecProperty: - return self.item.value - - @property - def path(self) -> tuple[int | str, ...]: - return self.item.path - - @property - def acc(self) -> T: - return self.item.acc - - @property - def type(self) -> str: - is_list_element = isinstance(self.path[-1], int) - if is_list_element: - return self.path[-2] - return self.path[-1] - - @cached_property - def parent(self) -> Optional["VisitedItem"]: - raw_parent = self.__parent() - if raw_parent is not None: - return VisitedItem(item=raw_parent, spec=self.spec) - return None - - def __parent(self) -> _VisitedItemRaw | None: - has_parent = len(self.path) > 1 - if has_parent: - parent_path = self.path[:-1] - parent_value = dict_value_by_path(self.spec, parent_path) - return _VisitedItemRaw(parent_value, parent_path, self.acc) - return None class BaseRenderer(ABC, Generic[T]): - """ - Base class for all renderers. - """ - - def __init__(self, spec: dict, df: DataFrame): - """ - Creates a new renderer for the specified specification and data frame. - - :param spec: dictionary-based specification - :param df: data frame to be rendered - """ - self.spec = spec - self.df = df - - def build(self) -> T: - """ - Builds a concrete rendering product of type `T` from `self.spec` and `self.df`. - The rendering object's actual type depends on the concrete renderer. - :return: product of the rendering - """ - - def traverse(dct: dict, path: tuple[str | int, ...], acc: T): - """ - Recursively visit a dictionary-based specification. - - :param dct: dictionary-based specification - :param path: path to the current node - :param acc: accumulated rendering product - :return: the most recent rendering product - """ - has_complex_children = any( - isinstance(v, dict) or isinstance(v, list) for v in dct.values() - ) - if not has_complex_children: - return self._visitor( - VisitedItem( - item=_VisitedItemRaw(value=dct, path=path, acc=acc), - spec=self.spec, - ) - ) - - for key, value in dct.items(): - if isinstance(value, dict): - acc = traverse(value, path + (key,), acc) - elif isinstance(value, list): - for i, item in enumerate(value): - acc = traverse(item, path + (key, i), acc) - else: - acc = self._visitor( - VisitedItem( - item=_VisitedItemRaw( - value=value, path=path + (key,), acc=acc - ), - spec=self.spec, - ) - ) - return acc - - product = traverse(dct=self.spec, path=(), acc=self._initial) - post_processed = self.post_build_hook(product) - return post_processed - - @property @abstractmethod - def _initial(self) -> T: - """ - :return: The initial rendering product to start with. - """ + def build(self, spec: SpecificationDict, data: DataFrame) -> T: raise NotImplementedError @abstractmethod - def _visitor(self, item: VisitedItem[T]) -> T: - """ - The callback to be invoked for each visited item of the specification. - Should be implemented by concrete renderers to produce the rendering product - step-by-step based on the contents of the supplied `payload`. - - :param item: the visited item - :return: the updated rendering product - """ + def display(self, product: T) -> None: raise NotImplementedError - def post_build_hook(self, product: T) -> T: - """ - Called after the traversal of the specification is completed. - Acts as a hook for post-processing the rendering product. - :return: the updated rendering product - """ - return product + def render(self, spec: SpecificationDict, data: DataFrame) -> None: + product = self.build(spec, data) + self.display(product) diff --git a/draco/renderer/vega_lite.py b/draco/renderer/vega_lite.py deleted file mode 100644 index e69de29b..00000000 diff --git a/draco/renderer/vega_lite_renderer.py b/draco/renderer/vega_lite_renderer.py deleted file mode 100644 index b95873d0..00000000 --- a/draco/renderer/vega_lite_renderer.py +++ /dev/null @@ -1,75 +0,0 @@ -import json - -from pandas import DataFrame - -from .base_renderer import BaseRenderer, VisitedItem - - -class VegaLiteRenderer(BaseRenderer[dict]): - def __init__(self, spec: dict, df: DataFrame): - super().__init__(spec, df) - - @property - def _initial(self) -> dict: - return { - "$schema": "https://vega.github.io/schema/vega-lite/v5.2.0.json", - } - - def _visitor(self, item: VisitedItem) -> dict: - match item.type: - case "mark": - pass - case "encoding": - pass - case "scale": - pass - return item.acc - - def post_build_hook(self, product: dict) -> dict: - # add data to VL spec - data = self.df.to_dict(orient="records") - product["data"] = {"values": data} - return product - - __DATA_TYPE_MAP__ = { - "number": "quantitative", - "string": "nominal", - } - - -if __name__ == "__main__": - from pprint import pprint - - from draco.fact_utils import answer_set_to_dict - from draco.run import run_clingo - - def facts_to_dict(facts: list[str]): - result = run_clingo(facts) - return answer_set_to_dict(next(result).answer_set) - - facts = [ - "attribute(number_rows,root,100).", - "entity(field,root,temperature).", - "attribute((field,name),temperature,temperature).", - "attribute((field,type),temperature,number).", - "entity(view,root,0).", - "entity(mark,0,1).", - "attribute((mark,type),1,tick).", - "entity(encoding,1,2).", - "attribute((encoding,channel),2,x).", - "attribute((encoding,field),2,temperature).", - "entity(scale,0,3).", - "attribute((scale,channel),3,x).", - "attribute((scale,type),3,linear).", - ] - spec = facts_to_dict(facts) - - pprint(spec) - print() - - df = DataFrame.from_records( - data=[dict(a=i, b=25 * i, c=50 * i) for i in range(1, 11)] - ) - vl = VegaLiteRenderer(dict(spec), df) - product = vl.build() - print(json.dumps(product, indent=2)) diff --git a/draco/types.py b/draco/types.py index fc57be5a..9348fa7c 100644 --- a/draco/types.py +++ b/draco/types.py @@ -1,3 +1,230 @@ -from typing import Iterable, TypeAlias +from typing import Iterable, Literal, TypeAlias + +import pydantic Specification: TypeAlias = Iterable[str] | str + +""" +The number of rows in the dataset. +""" +DatasetNumberRows = pydantic.PositiveInt + +""" +The name of a data field. +Described as `(field,name)` +""" +FieldName = str + +""" +The type of the data in the column for this field. +One of number, string, boolean, or datetime. +Described as `(field,type)` +""" +FieldType = Literal["number", "string", "boolean", "datetime"] + +""" +The number of unique values. +Described as `(field,unique)` +""" +FieldUnique = pydantic.PositiveInt + +""" +The entropy of the field. +Described as `(field,entropy)` +""" +FieldEntropy = pydantic.PositiveFloat + +""" +The minimum value. Only used for numbers. +Described as `(field,min)` +""" +FieldMin = float + +""" +The maximum value. Only used for numbers. +Described as `(field,max)` +""" +FieldMax = float + +""" +The standard deviation. Only used for numbers. +Described as `(field,std)` +""" +FieldStd = pydantic.confloat(ge=0) + +""" +The frequency of the most common value. Only used for strings. +Described as `(field,freq)` +""" +FieldFreq = pydantic.PositiveInt + +""" +When the task regards specific fields, fields can be marked as relevant to the task. +Described as `(field,interesting)` +""" +FieldInteresting = bool + +""" +The coordinates system of the view. Can be one of cartesian, or polar. +Described as `(view,coordinates)`. +""" +ViewCoordinate = Literal["cartesian", "polar"] + +""" +The mark type. One of point, bar, line, area, text, tick, or rect. +Described as `(mark,type)`. +""" +MarkType = Literal["point", "bar", "line", "area", "text", "tick", "rect"] + +""" +The visual channel. One of x, y, color, size, shape, or text. +Same as `ScaleChannel`. +Described as `(encoding,channel)`. +""" +EncodingChannel = Literal["x", "y", "color", "size", "shape", "text"] + +""" +The field that maps to the visual property of the mark. Arbitrary string. +Described as `(encoding,field)`. +""" +EncodingField = FieldName + +""" +How the data is aggregated. One of count, mean, median, min, max, stdev, or sum. +Described as `(encoding,aggregate)`. +""" +EncodingAggregate = Literal["count", "mean", "median", "min", "max", "stdev", "sum"] + +""" +How the data is binned into N bins. Positive integer. +Described as `(encoding,binning)` +""" +EncodingBinning = pydantic.PositiveInt + +""" +Stacking strategy. One of zero, center, or normalize. +Described as `(encoding,stack)`. +""" +EncodingStack = Literal["zero", "center", "normalize"] + +""" +The scale channel. One of x, y, color, size, shape, or text. +Same as `EncodingChannel`. +Described as `(scale,channel)`. +""" +ScaleChannel = EncodingChannel + +""" +The scale type. One of linear, log, ordinal, or categorical. +Described as `(scale,type)`. +""" +ScaleType = Literal["linear", "log", "ordinal", "categorical"] + +""" +Whether to include zero in the scale domain. +Described as `(scale,zero)`. +""" +ScaleZero = bool + +""" +The facet channel. Can be one of col and row. +Described as `(facet,channel)`. +""" +FacetChannel = Literal["col", "row"] + +""" +The facet field. Arbitrary string. +Described as `(facet,field)`. +""" +FacetField = FieldName + +""" +Binning a numeric field for faceting. Positive integer. +Described as `(facet,binning)`. +""" +FacetBinning = EncodingBinning + + +class SchemaBase(pydantic.BaseModel): + class Config: + extra = pydantic.Extra.forbid + + +class Encoding(SchemaBase): + channel: EncodingChannel + field: EncodingField | None = None + aggregate: EncodingAggregate | None = None + binning: EncodingBinning | None = None + stack: EncodingStack | None = None + + @pydantic.root_validator(pre=True) + def check_field_is_present_unless_agg_count(cls, values: dict): + if values.get("aggregate", None) != "count" and "field" not in values: + raise ValueError("field must be present unless aggregate is count") + return values + + +class Mark(SchemaBase): + type: MarkType + encoding: list[Encoding] + + +class Scale(SchemaBase): + channel: ScaleChannel + type: ScaleType = pydantic.Field(default="linear") + zero: ScaleZero | None = None + + +class Facet(SchemaBase): + channel: FacetChannel + field: FacetField + binning: FacetBinning | None = None + + +class View(SchemaBase): + coordinates: ViewCoordinate = pydantic.Field(default="cartesian") + mark: list[Mark] + scale: list[Scale] | None = None + facet: list[Facet] | None = None + + +class Field(SchemaBase): + name: FieldName + type: FieldType + unique: FieldUnique | None = None + entropy: FieldEntropy | None = None + min: FieldMin | None = None + max: FieldMax | None = None + std: FieldStd | None = None + freq: FieldFreq | None = None + interesting: FieldInteresting | None = None + + __STRING_ONLY_FIELDS__ = {"freq"} + __NUMBER_ONLY_FIELDS__ = {"min", "max", "std"} + + @pydantic.root_validator(pre=True) + def check_no_string_attributes_on_number_type(cls, values: dict): + if values["type"] == "number": + for field in cls.__STRING_ONLY_FIELDS__: + if field in values: + raise ValueError( + f"{field} is not a valid attribute for a number field" + ) + return values + + @pydantic.root_validator(pre=True) + def check_no_number_attributes_on_string_type(cls, values: dict): + if values["type"] == "string": + for field in cls.__NUMBER_ONLY_FIELDS__: + if field in values: + raise ValueError( + f"{field} is not a valid attribute for a string field" + ) + return values + + +class SpecificationDict(SchemaBase): + number_rows: DatasetNumberRows + field: list[Field] + view: list[View] + scale: list[Scale] | None = None From 43644e6fbbe1a0807b6fad9d471d76628f0839ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Thu, 10 Nov 2022 18:03:12 +0100 Subject: [PATCH 07/45] chore: update `mypy` The previous version crashed for some cases including `Generic` types --- poetry.lock | 2327 ++++++++---------------------------------------- pyproject.toml | 2 +- 2 files changed, 381 insertions(+), 1948 deletions(-) diff --git a/poetry.lock b/poetry.lock index 4a81e27d..b43cdcb7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -23,7 +23,7 @@ pandas = ">=0.18" toolz = "*" [package.extras] -dev = ["black", "docutils", "flake8", "ipython", "m2r", "mistune (<2.0.0)", "pytest", "recommonmark", "sphinx", "vega-datasets"] +dev = ["black", "docutils", "ipython", "flake8", "pytest", "sphinx", "mistune (<2.0.0)", "m2r", "vega-datasets", "recommonmark"] [[package]] name = "anyio" @@ -38,8 +38,8 @@ idna = ">=2.8" sniffio = ">=1.1" [package.extras] -doc = ["packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["contextlib2", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "uvloop (>=0.15)"] +doc = ["packaging", "sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"] +test = ["coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "contextlib2", "uvloop (<0.15)", "mock (>=4)", "uvloop (>=0.15)"] trio = ["trio (>=0.16,<0.22)"] [[package]] @@ -62,8 +62,8 @@ python-versions = ">=3.6" argon2-cffi-bindings = "*" [package.extras] -dev = ["cogapp", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "pre-commit", "pytest", "sphinx", "sphinx-notfound-page", "tomli"] -docs = ["furo", "sphinx", "sphinx-notfound-page"] +dev = ["pre-commit", "cogapp", "tomli", "coverage[toml] (>=5.0.2)", "hypothesis", "pytest", "sphinx", "sphinx-notfound-page", "furo"] +docs = ["sphinx", "sphinx-notfound-page", "furo"] tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pytest"] [[package]] @@ -78,12 +78,12 @@ python-versions = ">=3.6" cffi = ">=1.0.1" [package.extras] -dev = ["cogapp", "pre-commit", "pytest", "wheel"] +dev = ["pytest", "cogapp", "pre-commit", "wheel"] tests = ["pytest"] [[package]] name = "asttokens" -version = "2.0.8" +version = "2.1.0" description = "Annotate AST trees with source code positions" category = "dev" optional = false @@ -104,14 +104,14 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [package.extras] -dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "six", "sphinx", "sphinx-notfound-page", "zope.interface"] -docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] -tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "six", "zope.interface"] -tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "six"] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"] +docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"] [[package]] name = "babel" -version = "2.10.3" +version = "2.11.0" description = "Internationalization utilities" category = "dev" optional = false @@ -180,7 +180,7 @@ webencodings = "*" [package.extras] css = ["tinycss2 (>=1.1.0,<1.2)"] -dev = ["Sphinx (==4.3.2)", "black (==22.3.0)", "build (==0.8.0)", "flake8 (==4.0.1)", "hashin (==0.17.0)", "mypy (==0.961)", "pip-tools (==6.6.2)", "pytest (==7.1.2)", "tox (==3.25.0)", "twine (==4.0.1)", "wheel (==0.37.1)"] +dev = ["build (==0.8.0)", "flake8 (==4.0.1)", "hashin (==0.17.0)", "pip-tools (==6.6.2)", "pytest (==7.1.2)", "Sphinx (==4.3.2)", "tox (==3.25.0)", "twine (==4.0.1)", "wheel (==0.37.1)", "black (==22.3.0)", "mypy (==0.961)"] [[package]] name = "certifi" @@ -218,7 +218,7 @@ optional = false python-versions = ">=3.6.0" [package.extras] -unicode-backport = ["unicodedata2"] +unicode_backport = ["unicodedata2"] [[package]] name = "click" @@ -233,7 +233,7 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} [[package]] name = "clingo" -version = "5.6.1" +version = "5.6.2" description = "CFFI-based bindings to the clingo solver." category = "main" optional = false @@ -244,15 +244,15 @@ cffi = "*" [[package]] name = "colorama" -version = "0.4.5" +version = "0.4.6" description = "Cross-platform colored terminal text." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" [[package]] name = "contourpy" -version = "1.0.5" +version = "1.0.6" description = "Python library for calculating contours of 2D quadrilateral grids" category = "main" optional = false @@ -263,10 +263,10 @@ numpy = ">=1.16" [package.extras] bokeh = ["bokeh", "selenium"] -docs = ["docutils (<0.18)", "sphinx", "sphinx-rtd-theme"] -test = ["Pillow", "flake8", "isort", "matplotlib", "pytest"] +docs = ["docutils (<0.18)", "sphinx (<=5.2.0)", "sphinx-rtd-theme"] +test = ["pytest", "matplotlib", "pillow", "flake8", "isort"] test-minimal = ["pytest"] -test-no-codebase = ["Pillow", "matplotlib", "pytest"] +test-no-codebase = ["pytest", "matplotlib", "pillow"] [[package]] name = "coverage" @@ -340,7 +340,7 @@ python-versions = ">=3.6" [[package]] name = "exceptiongroup" -version = "1.0.0" +version = "1.0.1" description = "Backport of PEP 654 (exception groups)" category = "dev" optional = false @@ -351,18 +351,18 @@ test = ["pytest (>=6)"] [[package]] name = "executing" -version = "1.1.1" +version = "1.2.0" description = "Get the currently executing AST node of a frame, and other information" category = "dev" optional = false python-versions = "*" [package.extras] -tests = ["asttokens", "littleutils", "pytest", "rich"] +tests = ["asttokens", "pytest", "littleutils", "rich"] [[package]] name = "fastapi" -version = "0.85.1" +version = "0.85.2" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "main" optional = false @@ -375,8 +375,8 @@ starlette = "0.20.4" [package.extras] all = ["email-validator (>=1.1.1,<2.0.0)", "itsdangerous (>=1.1.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "orjson (>=3.2.1,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "requests (>=2.24.0,<3.0.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)", "uvicorn[standard] (>=0.12.0,<0.19.0)"] dev = ["autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "pre-commit (>=2.17.0,<3.0.0)", "uvicorn[standard] (>=0.12.0,<0.19.0)"] -doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer (>=0.4.1,<0.7.0)"] -test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.8.0)", "databases[sqlite] (>=0.3.2,<0.7.0)", "email-validator (>=1.1.1,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.23.0,<0.24.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.971)", "orjson (>=3.2.1,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=7.1.3,<8.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "requests (>=2.24.0,<3.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "types-orjson (==3.6.2)", "types-ujson (==5.4.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] +doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer[all] (>=0.6.1,<0.7.0)"] +test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.8.0)", "databases[sqlite] (>=0.3.2,<0.7.0)", "email-validator (>=1.1.1,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.23.0,<0.24.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.982)", "orjson (>=3.2.1,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest-cov (>=2.12.0,<5.0.0)", "pytest (>=7.1.3,<8.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "requests (>=2.24.0,<3.0.0)", "sqlalchemy (>=1.3.18,<=1.4.41)", "types-orjson (==3.6.2)", "types-ujson (==5.5.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] [[package]] name = "fastjsonschema" @@ -387,7 +387,7 @@ optional = false python-versions = "*" [package.extras] -devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"] +devel = ["colorama", "jsonschema", "json-spec", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"] [[package]] name = "filelock" @@ -429,16 +429,16 @@ tomli = "*" [[package]] name = "fonttools" -version = "4.37.4" +version = "4.38.0" description = "Tools to manipulate font files" category = "main" optional = false python-versions = ">=3.7" [package.extras] -all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=14.0.0)", "xattr", "zopfli (>=0.1.4)"] +all = ["fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "zopfli (>=0.1.4)", "lz4 (>=1.7.4.2)", "matplotlib", "sympy", "skia-pathops (>=0.5.0)", "uharfbuzz (>=0.23.0)", "brotlicffi (>=0.8.0)", "scipy", "brotli (>=1.0.1)", "munkres", "unicodedata2 (>=14.0.0)", "xattr"] graphite = ["lz4 (>=1.7.4.2)"] -interpolatable = ["munkres", "scipy"] +interpolatable = ["scipy", "munkres"] lxml = ["lxml (>=4.0,<5)"] pathops = ["skia-pathops (>=0.5.0)"] plot = ["matplotlib"] @@ -447,7 +447,7 @@ symfont = ["sympy"] type1 = ["xattr"] ufo = ["fs (>=2.2.0,<3)"] unicode = ["unicodedata2 (>=14.0.0)"] -woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] +woff = ["zopfli (>=0.1.4)", "brotlicffi (>=0.8.0)", "brotli (>=1.0.1)"] [[package]] name = "gitdb" @@ -473,14 +473,15 @@ gitdb = ">=4.0.1,<5" [[package]] name = "greenlet" -version = "1.1.3.post0" +version = "2.0.1" description = "Lightweight in-process concurrent programming" category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" [package.extras] -docs = ["Sphinx"] +docs = ["sphinx", "docutils (<0.18)"] +test = ["objgraph", "psutil", "faulthandler"] [[package]] name = "h11" @@ -492,7 +493,7 @@ python-versions = ">=3.7" [[package]] name = "identify" -version = "2.5.6" +version = "2.5.8" description = "File identification library for Python" category = "dev" optional = false @@ -540,9 +541,9 @@ python-versions = ">=3.7" zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] +docs = ["sphinx (>=3.5)", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "furo", "jaraco.tidelift (>=1.4)"] perf = ["ipython"] -testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "flake8 (<5)", "pytest-cov", "pytest-enabler (>=1.3)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"] [[package]] name = "iniconfig" @@ -554,11 +555,11 @@ python-versions = "*" [[package]] name = "ipykernel" -version = "6.16.1" +version = "6.17.1" description = "IPython Kernel for Jupyter" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" [package.dependencies] appnope = {version = "*", markers = "platform_system == \"Darwin\""} @@ -575,11 +576,11 @@ traitlets = ">=5.1.0" [package.extras] docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinxcontrib-github-alt"] -test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-cov", "pytest-timeout"] +test = ["flaky", "ipyparallel", "pre-commit", "pytest-cov", "pytest-timeout", "pytest (>=7.0)"] [[package]] name = "ipython" -version = "8.5.0" +version = "8.6.0" description = "IPython: Productive Interactive Computing" category = "dev" optional = false @@ -600,9 +601,9 @@ stack-data = "*" traitlets = ">=5" [package.extras] -all = ["Sphinx (>=1.3)", "black", "curio", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.19)", "pandas", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "testpath", "trio"] +all = ["black", "ipykernel", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "docrepr", "matplotlib", "stack-data", "pytest (<7)", "typing-extensions", "pytest (<7.1)", "pytest-asyncio", "testpath", "nbconvert", "nbformat", "ipywidgets", "notebook", "ipyparallel", "qtconsole", "curio", "matplotlib (!=3.2.0)", "numpy (>=1.20)", "pandas", "trio"] black = ["black"] -doc = ["Sphinx (>=1.3)"] +doc = ["ipykernel", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "docrepr", "matplotlib", "stack-data", "pytest (<7)", "typing-extensions", "pytest (<7.1)", "pytest-asyncio", "testpath"] kernel = ["ipykernel"] nbconvert = ["nbconvert"] nbformat = ["nbformat"] @@ -610,7 +611,7 @@ notebook = ["ipywidgets", "notebook"] parallel = ["ipyparallel"] qtconsole = ["qtconsole"] test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] -test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.19)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] +test_extra = ["pytest (<7.1)", "pytest-asyncio", "testpath", "curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.20)", "pandas", "trio"] [[package]] name = "ipython-genutils" @@ -637,7 +638,7 @@ traitlets = ">=4.3.1" widgetsnbextension = ">=3.6.0,<3.7.0" [package.extras] -test = ["mock", "pytest (>=3.6.0)", "pytest-cov"] +test = ["pytest (>=3.6.0)", "pytest-cov", "mock"] [[package]] name = "isort" @@ -648,10 +649,10 @@ optional = false python-versions = ">=3.6.1,<4.0" [package.extras] +pipfile_deprecated_finder = ["pipreqs", "requirementslib"] +requirements_deprecated_finder = ["pipreqs", "pip-api"] colors = ["colorama (>=0.4.3,<0.5.0)"] -pipfile-deprecated-finder = ["pipreqs", "requirementslib"] plugins = ["setuptools"] -requirements-deprecated-finder = ["pip-api", "pipreqs"] [[package]] name = "jedi" @@ -712,12 +713,11 @@ python-versions = "*" [package.dependencies] attrs = ">=17.4.0" pyrsistent = ">=0.14.0" -setuptools = "*" six = ">=1.11.0" [package.extras] format = ["idna", "jsonpointer (>1.13)", "rfc3987", "strict-rfc3339", "webcolors"] -format-nongpl = ["idna", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "webcolors"] +format_nongpl = ["idna", "jsonpointer (>1.13)", "webcolors", "rfc3986-validator (>0.1.0)", "rfc3339-validator"] [[package]] name = "jupyter-book" @@ -748,10 +748,10 @@ sphinx_togglebutton = "*" sphinxcontrib-bibtex = ">=2.2.0,<=2.5.0" [package.extras] -code-style = ["pre-commit (>=2.12,<3.0)"] +code_style = ["pre-commit (>=2.12,<3.0)"] pdfhtml = ["pyppeteer"] -sphinx = ["altair", "bokeh", "folium", "ipywidgets", "jupytext", "matplotlib", "nbclient", "numpy", "pandas", "plotly", "sphinx-click", "sphinx-examples", "sphinx-proof", "sphinx_inline_tabs", "sphinxext-rediraffe (>=0.2.3,<0.3.0)", "sympy"] -testing = ["altair", "beautifulsoup4", "beautifulsoup4", "cookiecutter", "coverage", "jupytext", "matplotlib", "pyppeteer", "pytest (>=6.2.4)", "pytest-cov", "pytest-regressions", "pytest-timeout", "pytest-xdist", "sphinx_click", "sphinx_tabs", "texsoup"] +sphinx = ["altair", "bokeh", "folium", "ipywidgets", "jupytext", "matplotlib", "nbclient", "numpy", "pandas", "plotly", "sphinx-click", "sphinx-examples", "sphinx-inline-tabs", "sphinx-proof", "sphinxext-rediraffe (>=0.2.3,<0.3.0)", "sympy"] +testing = ["altair", "beautifulsoup4", "beautifulsoup4", "cookiecutter", "coverage", "jupytext", "matplotlib", "pyppeteer", "pytest (>=6.2.4)", "pytest-cov", "pytest-regressions", "pytest-timeout", "pytest-xdist", "sphinx-click", "sphinx-tabs", "texsoup"] [[package]] name = "jupyter-cache" @@ -769,14 +769,14 @@ nbformat = "*" sqlalchemy = ">=1.3.12,<1.5" [package.extras] -cli = ["click", "click-completion", "click-log", "pyyaml", "tabulate"] -code-style = ["black", "flake8 (>=3.7.0,<3.8.0)", "pre-commit (==1.17.0)"] -rtd = ["myst-nb (>=0.7,<1.0)", "pydata-sphinx-theme", "sphinx-copybutton"] -testing = ["coverage", "ipykernel", "matplotlib", "nbformat (>=5.1)", "numpy", "pandas", "pytest (>=3.6,<4)", "pytest-cov", "pytest-regressions", "sympy"] +testing = ["nbformat (>=5.1)", "pandas", "sympy", "numpy", "matplotlib", "pytest-regressions", "pytest-cov", "pytest (>=3.6,<4)", "coverage", "ipykernel"] +rtd = ["pydata-sphinx-theme", "sphinx-copybutton", "myst-nb (>=0.7,<1.0)"] +code_style = ["pre-commit (==1.17.0)", "black", "flake8 (>=3.7.0,<3.8.0)"] +cli = ["pyyaml", "tabulate", "click-log", "click-completion", "click"] [[package]] name = "jupyter-client" -version = "7.4.3" +version = "7.4.5" description = "Jupyter protocol implementation and client libraries" category = "dev" optional = false @@ -792,18 +792,19 @@ tornado = ">=6.2" traitlets = "*" [package.extras] -doc = ["ipykernel", "myst-parser", "sphinx (>=1.3.6)", "sphinx-rtd-theme", "sphinxcontrib-github-alt"] +doc = ["ipykernel", "myst-parser", "sphinx-rtd-theme", "sphinx (>=1.3.6)", "sphinxcontrib-github-alt"] test = ["codecov", "coverage", "ipykernel (>=6.12)", "ipython", "mypy", "pre-commit", "pytest", "pytest-asyncio (>=0.18)", "pytest-cov", "pytest-timeout"] [[package]] name = "jupyter-core" -version = "4.11.2" +version = "5.0.0" description = "Jupyter core package. A base package on which Jupyter projects rely." category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" [package.dependencies] +platformdirs = "*" pywin32 = {version = ">=1.0", markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""} traitlets = "*" @@ -812,8 +813,8 @@ test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"] [[package]] name = "jupyter-server" -version = "1.21.0" -description = "The backend—i.e. core services, APIs, and REST endpoints—to Jupyter web applications." +version = "1.23.1" +description = "=?utf-8?q?The_backend=E2=80=94i=2Ee=2E_core_services=2C_APIs=2C_and_REST_endpoints=E2=80=94to_Jupyter_web_applications=2E?=" category = "dev" optional = false python-versions = ">=3.7" @@ -837,7 +838,7 @@ traitlets = ">=5.1" websocket-client = "*" [package.extras] -test = ["coverage", "ipykernel", "pre-commit", "pytest (>=7.0)", "pytest-console-scripts", "pytest-cov", "pytest-mock", "pytest-timeout", "pytest-tornasync", "requests"] +test = ["coverage", "ipykernel", "pre-commit", "pytest-console-scripts", "pytest-cov", "pytest-mock", "pytest-timeout", "pytest-tornasync", "pytest (>=7.0)", "requests"] [[package]] name = "jupyter-server-mathjax" @@ -851,7 +852,7 @@ python-versions = ">=3.7" jupyter-server = ">=1.1" [package.extras] -test = ["jupyter-server[test]", "pytest"] +test = ["pytest", "jupyter-server"] [[package]] name = "jupyter-sphinx" @@ -889,7 +890,7 @@ tomli = "*" tornado = ">=6.1.0" [package.extras] -test = ["check-manifest", "coverage", "jupyterlab-server[test]", "pre-commit", "pytest (>=6.0)", "pytest-check-links (>=0.5)", "pytest-console-scripts", "pytest-cov", "requests", "requests-cache", "virtualenv"] +test = ["check-manifest", "coverage", "jupyterlab-server", "pre-commit", "pytest (>=6.0)", "pytest-cov", "pytest-console-scripts", "pytest-check-links (>=0.5)", "requests", "requests-cache", "virtualenv"] ui-tests = ["build"] [[package]] @@ -902,7 +903,7 @@ python-versions = ">=3.7" [[package]] name = "jupyterlab-server" -version = "2.16.1" +version = "2.16.2" description = "A set of server components for JupyterLab and JupyterLab like applications." category = "dev" optional = false @@ -920,7 +921,7 @@ requests = "*" [package.extras] docs = ["autodoc-traits", "docutils (<0.19)", "jinja2 (<3.1.0)", "mistune (<1)", "myst-parser", "pydata-sphinx-theme", "sphinx", "sphinx-copybutton", "sphinxcontrib-openapi"] openapi = ["openapi-core (>=0.14.2)", "ruamel-yaml"] -test = ["codecov", "ipykernel", "jupyter-server[test]", "openapi-core (>=0.14.2,<0.15.0)", "openapi-spec-validator (<0.5)", "pytest (>=7.0)", "pytest-console-scripts", "pytest-cov", "ruamel-yaml", "strict-rfc3339"] +test = ["codecov", "ipykernel", "jupyter-server", "openapi-core (>=0.14.2,<0.15.0)", "openapi-spec-validator (<0.5)", "pytest-console-scripts", "pytest-cov", "pytest (>=7.0)", "ruamel-yaml", "strict-rfc3339"] [[package]] name = "jupyterlab-widgets" @@ -951,7 +952,7 @@ six = ">=1.4.1" [[package]] name = "libcst" -version = "0.4.7" +version = "0.4.8" description = "A concrete syntax tree with AST-like properties for Python 3.5, 3.6, 3.7, 3.8, 3.9, and 3.10 programs." category = "dev" optional = false @@ -963,7 +964,7 @@ typing-extensions = ">=3.7.4.2" typing-inspect = ">=0.4.0" [package.extras] -dev = ["black (==22.3.0)", "coverage (>=4.5.4)", "fixit (==0.1.1)", "flake8 (>=3.7.8)", "hypothesis (>=4.36.0)", "hypothesmith (>=0.0.4)", "jinja2 (==3.0.3)", "jupyter (>=1.0.0)", "maturin (>=0.8.3,<0.9)", "nbsphinx (>=0.4.2)", "prompt-toolkit (>=2.0.9)", "pyre-check (==0.9.9)", "setuptools-rust (>=0.12.1)", "setuptools-scm (>=6.0.1)", "slotscheck (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "ufmt (==1.3)", "usort (==1.0.0rc1)"] +dev = ["black (==22.10.0)", "coverage (>=4.5.4)", "fixit (==0.1.1)", "flake8 (>=3.7.8,<5)", "Sphinx (>=5.1.1)", "hypothesis (>=4.36.0)", "hypothesmith (>=0.0.4)", "jupyter (>=1.0.0)", "maturin (>=0.8.3,<0.14)", "nbsphinx (>=0.4.2)", "prompt-toolkit (>=2.0.9)", "setuptools-scm (>=6.0.1)", "sphinx-rtd-theme (>=0.4.3)", "ufmt (==2.0.1)", "usort (==1.0.5)", "setuptools-rust (>=0.12.1)", "slotscheck (>=0.7.1)", "jinja2 (==3.1.2)", "pyre-check (==0.9.9)"] [[package]] name = "linkify-it-py" @@ -977,10 +978,10 @@ python-versions = ">=3.6" uc-micro-py = "*" [package.extras] -benchmark = ["pytest", "pytest-benchmark"] +test = ["pytest-cov", "pytest", "coverage"] +doc = ["myst-parser", "sphinx-book-theme", "sphinx"] dev = ["black", "flake8", "isort", "pre-commit"] -doc = ["myst-parser", "sphinx", "sphinx-book-theme"] -test = ["coverage", "pytest", "pytest-cov"] +benchmark = ["pytest-benchmark", "pytest"] [[package]] name = "lxml" @@ -993,7 +994,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" [package.extras] cssselect = ["cssselect (>=0.7)"] html5 = ["html5lib"] -htmlsoup = ["BeautifulSoup4"] +htmlsoup = ["beautifulsoup4"] source = ["Cython (>=0.29.7)"] [[package]] @@ -1008,12 +1009,12 @@ python-versions = "~=3.6" attrs = ">=19,<22" [package.extras] -code-style = ["pre-commit (==2.6)"] -compare = ["commonmark (>=0.9.1,<0.10.0)", "markdown (>=3.2.2,<3.3.0)", "mistletoe-ebp (>=0.10.0,<0.11.0)", "mistune (>=0.8.4,<0.9.0)", "panflute (>=1.12,<2.0)"] -linkify = ["linkify-it-py (>=1.0,<2.0)"] +testing = ["pytest-regressions", "pytest-cov", "pytest-benchmark (>=3.2,<4.0)", "pytest (>=3.6,<4)", "psutil", "coverage"] +rtd = ["sphinx-book-theme", "sphinx-panels (>=0.4.0,<0.5.0)", "sphinx-copybutton", "sphinx (>=2,<4)", "pyyaml", "myst-nb (==0.13.0a1)"] plugins = ["mdit-py-plugins"] -rtd = ["myst-nb (==0.13.0a1)", "pyyaml", "sphinx (>=2,<4)", "sphinx-book-theme", "sphinx-copybutton", "sphinx-panels (>=0.4.0,<0.5.0)"] -testing = ["coverage", "psutil", "pytest (>=3.6,<4)", "pytest-benchmark (>=3.2,<4.0)", "pytest-cov", "pytest-regressions"] +linkify = ["linkify-it-py (>=1.0,<2.0)"] +compare = ["panflute (>=1.12,<2.0)", "mistune (>=0.8.4,<0.9.0)", "mistletoe-ebp (>=0.10.0,<0.11.0)", "markdown (>=3.2.2,<3.3.0)", "commonmark (>=0.9.1,<0.10.0)"] +code_style = ["pre-commit (==2.6)"] [[package]] name = "markupsafe" @@ -1025,7 +1026,7 @@ python-versions = ">=3.7" [[package]] name = "matplotlib" -version = "3.6.1" +version = "3.6.2" description = "Python plotting package" category = "main" optional = false @@ -1074,9 +1075,9 @@ python-versions = "~=3.6" markdown-it-py = ">=1.0,<2.0" [package.extras] -code-style = ["pre-commit (==2.6)"] -rtd = ["myst-parser (==0.14.0a3)", "sphinx-book-theme (>=0.1.0,<0.2.0)"] -testing = ["coverage", "pytest (>=3.6,<4)", "pytest-cov", "pytest-regressions"] +testing = ["pytest-regressions", "pytest-cov", "pytest (>=3.6,<4)", "coverage"] +rtd = ["sphinx-book-theme (>=0.1.0,<0.2.0)", "myst-parser (==0.14.0a3)"] +code_style = ["pre-commit (==2.6)"] [[package]] name = "mistune" @@ -1088,7 +1089,7 @@ python-versions = "*" [[package]] name = "mypy" -version = "0.982" +version = "0.990" description = "Optional static typing for Python" category = "dev" optional = false @@ -1101,6 +1102,7 @@ typing-extensions = ">=3.10" [package.extras] dmypy = ["psutil (>=4.0)"] +install-types = ["pip"] python2 = ["typed-ast (>=1.4.0,<2)"] reports = ["lxml"] @@ -1135,7 +1137,7 @@ sphinx = ">=3.1,<5" sphinx-togglebutton = ">=0.3.0,<0.4.0" [package.extras] -code-style = ["pre-commit (>=2.12,<3.0)"] +code_style = ["pre-commit (>=2.12,<3.0)"] rtd = ["alabaster", "altair", "bokeh", "coconut (>=1.4.3,<1.5.0)", "ipykernel (>=5.5,<6.0)", "ipywidgets", "jupytext (>=1.11.2,<1.12.0)", "matplotlib", "numpy", "pandas", "plotly", "sphinx-book-theme (>=0.1.0,<0.2.0)", "sphinx-copybutton", "sphinx-panels (>=0.4.1,<0.5.0)", "sphinxcontrib-bibtex", "sympy"] testing = ["coverage (<5.0)", "ipykernel (>=5.5,<6.0)", "ipython (<8)", "jupytext (>=1.11.2,<1.12.0)", "matplotlib (>=3.3.0,<3.4.0)", "numpy", "pandas (<1.4)", "pytest (>=5.4,<6.0)", "pytest-cov (>=2.8,<3.0)", "pytest-regressions", "sympy"] @@ -1156,14 +1158,14 @@ pyyaml = "*" sphinx = ">=3.1,<5" [package.extras] -code-style = ["pre-commit (>=2.12,<3.0)"] +code_style = ["pre-commit (>=2.12,<3.0)"] linkify = ["linkify-it-py (>=1.0,<2.0)"] -rtd = ["ipython", "sphinx-book-theme (>=0.1.0,<0.2.0)", "sphinx-panels (>=0.5.2,<0.6.0)", "sphinxcontrib-bibtex (>=2.1,<3.0)", "sphinxcontrib.mermaid (>=0.6.3,<0.7.0)", "sphinxext-opengraph (>=0.4.2,<0.5.0)", "sphinxext-rediraffe (>=0.2,<1.0)"] +rtd = ["ipython", "sphinx-book-theme (>=0.1.0,<0.2.0)", "sphinx-panels (>=0.5.2,<0.6.0)", "sphinxcontrib-bibtex (>=2.1,<3.0)", "sphinxext-rediraffe (>=0.2,<1.0)", "sphinxcontrib.mermaid (>=0.6.3,<0.7.0)", "sphinxext-opengraph (>=0.4.2,<0.5.0)"] testing = ["beautifulsoup4", "coverage", "docutils (>=0.17.0,<0.18.0)", "pytest (>=3.6,<4)", "pytest-cov", "pytest-regressions"] [[package]] name = "nbclassic" -version = "0.4.7" +version = "0.4.8" description = "A web-based notebook environment for interactive computing" category = "dev" optional = false @@ -1189,9 +1191,9 @@ tornado = ">=6.1" traitlets = ">=4.2.1" [package.extras] -docs = ["myst-parser", "nbsphinx", "sphinx", "sphinx-rtd-theme", "sphinxcontrib-github-alt"] +docs = ["sphinx", "nbsphinx", "sphinxcontrib-github-alt", "sphinx-rtd-theme", "myst-parser"] json-logging = ["json-logging"] -test = ["coverage", "nbval", "pytest", "pytest-cov", "pytest-tornasync", "requests", "requests-unixsocket", "selenium (==4.1.5)", "testpath"] +test = ["pytest", "coverage", "requests", "testpath", "nbval", "pytest-playwright", "pytest-cov", "pytest-tornasync", "requests-unixsocket"] [[package]] name = "nbclient" @@ -1208,8 +1210,8 @@ nest-asyncio = "*" traitlets = ">=5.0.0" [package.extras] -sphinx = ["Sphinx (>=1.7)", "mock", "moto", "myst-parser", "sphinx-book-theme"] -test = ["black", "check-manifest", "flake8", "ipykernel", "ipython (<8.0.0)", "ipywidgets (<8.0.0)", "mypy", "pip (>=18.1)", "pytest (>=4.1)", "pytest-asyncio", "pytest-cov (>=2.6.1)", "setuptools (>=38.6.0)", "twine (>=1.11.0)", "wheel (>=0.31.0)", "xmltodict"] +sphinx = ["Sphinx (>=1.7)", "sphinx-book-theme", "mock", "moto", "myst-parser"] +test = ["ipython (<8.0.0)", "ipykernel", "ipywidgets (<8.0.0)", "pytest (>=4.1)", "pytest-asyncio", "pytest-cov (>=2.6.1)", "check-manifest", "flake8", "mypy", "xmltodict", "black", "pip (>=18.1)", "wheel (>=0.31.0)", "setuptools (>=38.6.0)", "twine (>=1.11.0)"] [[package]] name = "nbconvert" @@ -1239,10 +1241,10 @@ tinycss2 = "*" traitlets = ">=5.0" [package.extras] -all = ["ipykernel", "ipython", "ipywidgets (>=7)", "nbsphinx (>=0.2.12)", "pre-commit", "pyppeteer (>=1,<1.1)", "pytest", "pytest-cov", "pytest-dependency", "sphinx (>=1.5.1)", "sphinx-rtd-theme", "tornado (>=6.1)"] -docs = ["ipython", "nbsphinx (>=0.2.12)", "sphinx (>=1.5.1)", "sphinx-rtd-theme"] +all = ["pytest", "pytest-cov", "pytest-dependency", "ipykernel", "ipywidgets (>=7)", "pre-commit", "pyppeteer (>=1,<1.1)", "tornado (>=6.1)", "sphinx (>=1.5.1)", "sphinx-rtd-theme", "nbsphinx (>=0.2.12)", "ipython"] +docs = ["sphinx (>=1.5.1)", "sphinx-rtd-theme", "nbsphinx (>=0.2.12)", "ipython"] serve = ["tornado (>=6.1)"] -test = ["ipykernel", "ipywidgets (>=7)", "pre-commit", "pyppeteer (>=1,<1.1)", "pytest", "pytest-cov", "pytest-dependency"] +test = ["pytest", "pytest-cov", "pytest-dependency", "ipykernel", "ipywidgets (>=7)", "pre-commit", "pyppeteer (>=1,<1.1)"] webpdf = ["pyppeteer (>=1,<1.1)"] [[package]] @@ -1265,8 +1267,8 @@ requests = "*" tornado = "*" [package.extras] -docs = ["recommonmark", "sphinx", "sphinx-rtd-theme"] -test = ["jsonschema", "jupyter-server[test]", "mock", "notebook", "pytest (>=3.6)", "pytest-cov", "pytest-timeout", "pytest-tornado", "requests", "tabulate"] +docs = ["sphinx", "recommonmark", "sphinx-rtd-theme"] +test = ["pytest (>=3.6)", "pytest-cov", "pytest-timeout", "pytest-tornado", "jupyter-server", "jsonschema", "mock", "notebook", "requests", "tabulate"] [[package]] name = "nbformat" @@ -1302,15 +1304,15 @@ optional = false python-versions = ">=3.8" [package.extras] -default = ["matplotlib (>=3.4)", "numpy (>=1.19)", "pandas (>=1.3)", "scipy (>=1.8)"] -developer = ["mypy (>=0.960)", "pre-commit (>=2.19)"] -doc = ["nb2plots (>=0.6)", "numpydoc (>=1.3)", "pillow (>=9.1)", "pydata-sphinx-theme (>=0.8.1)", "sphinx (>=4.5)", "sphinx-gallery (>=0.10)", "texext (>=0.6.6)"] -extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.9)", "sympy (>=1.10)"] -test = ["codecov (>=2.1)", "pytest (>=7.1)", "pytest-cov (>=3.0)"] +default = ["numpy (>=1.19)", "scipy (>=1.8)", "matplotlib (>=3.4)", "pandas (>=1.3)"] +developer = ["pre-commit (>=2.19)", "mypy (>=0.960)"] +doc = ["sphinx (>=4.5)", "pydata-sphinx-theme (>=0.8.1)", "sphinx-gallery (>=0.10)", "numpydoc (>=1.3)", "pillow (>=9.1)", "nb2plots (>=0.6)", "texext (>=0.6.6)"] +extra = ["lxml (>=4.6)", "pygraphviz (>=1.9)", "pydot (>=1.4.2)", "sympy (>=1.10)"] +test = ["pytest (>=7.1)", "pytest-cov (>=3.0)", "codecov (>=2.1)"] [[package]] name = "ninja" -version = "1.10.2.4" +version = "1.11.1" description = "Ninja is a small build system with a focus on speed" category = "dev" optional = false @@ -1327,12 +1329,9 @@ category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" -[package.dependencies] -setuptools = "*" - [[package]] name = "notebook" -version = "6.5.0" +version = "6.5.2" description = "A web-based notebook environment for interactive computing" category = "dev" optional = false @@ -1345,7 +1344,7 @@ ipython-genutils = "*" jinja2 = "*" jupyter-client = ">=5.3.4" jupyter-core = ">=4.6.1" -nbclassic = ">=0.4.0" +nbclassic = ">=0.4.7" nbconvert = ">=5" nbformat = "*" nest-asyncio = ">=1.5" @@ -1357,13 +1356,13 @@ tornado = ">=6.1" traitlets = ">=4.2.1" [package.extras] -docs = ["myst-parser", "nbsphinx", "sphinx", "sphinx-rtd-theme", "sphinxcontrib-github-alt"] +docs = ["sphinx", "nbsphinx", "sphinxcontrib-github-alt", "sphinx-rtd-theme", "myst-parser"] json-logging = ["json-logging"] -test = ["coverage", "nbval", "pytest", "pytest-cov", "requests", "requests-unixsocket", "selenium (==4.1.5)", "testpath"] +test = ["pytest", "coverage", "requests", "testpath", "nbval", "selenium (==4.1.5)", "pytest-cov", "requests-unixsocket"] [[package]] name = "notebook-shim" -version = "0.2.0" +version = "0.2.2" description = "A shim layer for notebook traits and config" category = "dev" optional = false @@ -1408,7 +1407,7 @@ python-dateutil = ">=2.8.1" pytz = ">=2020.1" [package.extras] -test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] +test = ["pytest-xdist (>=1.31)", "pytest (>=6.0)", "hypothesis (>=5.5.3)"] [[package]] name = "pandas-stubs" @@ -1470,7 +1469,7 @@ python-versions = "*" [[package]] name = "pillow" -version = "9.2.0" +version = "9.3.0" description = "Python Imaging Library (Fork)" category = "main" optional = false @@ -1482,15 +1481,15 @@ tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "pa [[package]] name = "platformdirs" -version = "2.5.2" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +version = "2.5.3" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" [package.extras] -docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"] -test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] +docs = ["furo (>=2022.9.29)", "proselint (>=0.13)", "sphinx-autodoc-typehints (>=1.19.4)", "sphinx (>=5.3)"] +test = ["appdirs (==1.4.4)", "pytest-cov (>=4)", "pytest-mock (>=3.10)", "pytest (>=7.2)"] [[package]] name = "pluggy" @@ -1533,7 +1532,7 @@ twisted = ["twisted"] [[package]] name = "prompt-toolkit" -version = "3.0.31" +version = "3.0.32" description = "Library for building powerful interactive command lines in Python" category = "dev" optional = false @@ -1544,14 +1543,14 @@ wcwidth = "*" [[package]] name = "psutil" -version = "5.9.3" +version = "5.9.4" description = "Cross-platform lib for process and system monitoring in Python." category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [package.extras] -test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] +test = ["ipaddress", "mock", "enum34", "pywin32", "wmi"] [[package]] name = "ptyprocess" @@ -1654,10 +1653,10 @@ packaging = "*" sphinx = ">=3.5.4,<5" [package.extras] -coverage = ["codecov", "pydata-sphinx-theme[test]", "pytest-cov"] -dev = ["nox", "pre-commit", "pydata-sphinx-theme[coverage]", "pyyaml"] -doc = ["jupyter_sphinx", "myst-parser", "numpy", "numpydoc", "pandas", "plotly", "pytest", "pytest-regressions", "sphinx-sitemap", "sphinxext-rediraffe", "xarray"] -test = ["pydata-sphinx-theme[doc]", "pytest"] +dev = ["pydata-sphinx-theme", "nox", "pre-commit", "pyyaml"] +coverage = ["pydata-sphinx-theme", "codecov", "pytest-cov"] +test = ["pydata-sphinx-theme", "pytest"] +doc = ["xarray", "numpy", "plotly", "jupyter-sphinx", "sphinx-sitemap", "sphinxext-rediraffe", "pytest-regressions", "pytest", "pandas", "myst-parser", "numpydoc"] [[package]] name = "pydot" @@ -1698,11 +1697,11 @@ optional = false python-versions = ">=3.6.8" [package.extras] -diagrams = ["jinja2", "railroad-diagrams"] +diagrams = ["railroad-diagrams", "jinja2"] [[package]] name = "pyrsistent" -version = "0.18.1" +version = "0.19.2" description = "Persistent/Functional/Immutable data structures" category = "dev" optional = false @@ -1741,7 +1740,7 @@ coverage = {version = ">=5.2.1", extras = ["toml"]} pytest = ">=4.6" [package.extras] -testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] +testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"] [[package]] name = "python-dateutil" @@ -1775,7 +1774,7 @@ typing-extensions = ">=4.3.0" [[package]] name = "pytz" -version = "2022.5" +version = "2022.6" description = "World timezone definitions, modern and historical" category = "main" optional = false @@ -1783,7 +1782,7 @@ python-versions = "*" [[package]] name = "pywin32" -version = "304" +version = "305" description = "Python for Window Extensions" category = "dev" optional = false @@ -1791,7 +1790,7 @@ python-versions = "*" [[package]] name = "pywinpty" -version = "2.0.8" +version = "2.0.9" description = "Pseudo terminal support for Windows from Python." category = "dev" optional = false @@ -1833,7 +1832,7 @@ urllib3 = ">=1.21.1,<1.27" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "scikit-learn" @@ -1850,10 +1849,10 @@ scipy = ">=1.3.2" threadpoolctl = ">=2.0.0" [package.extras] -benchmark = ["matplotlib (>=3.1.2)", "memory-profiler (>=0.57.0)", "pandas (>=1.0.5)"] -docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.1.2)", "memory-profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.0.5)", "scikit-image (>=0.16.2)", "seaborn (>=0.9.0)", "sphinx (>=4.0.1)", "sphinx-gallery (>=0.7.0)", "sphinx-prompt (>=1.3.0)", "sphinxext-opengraph (>=0.4.2)"] -examples = ["matplotlib (>=3.1.2)", "pandas (>=1.0.5)", "scikit-image (>=0.16.2)", "seaborn (>=0.9.0)"] -tests = ["black (>=22.3.0)", "flake8 (>=3.8.2)", "matplotlib (>=3.1.2)", "mypy (>=0.961)", "numpydoc (>=1.2.0)", "pandas (>=1.0.5)", "pyamg (>=4.0.0)", "pytest (>=5.0.1)", "pytest-cov (>=2.9.0)", "scikit-image (>=0.16.2)"] +benchmark = ["matplotlib (>=3.1.2)", "pandas (>=1.0.5)", "memory-profiler (>=0.57.0)"] +docs = ["matplotlib (>=3.1.2)", "scikit-image (>=0.16.2)", "pandas (>=1.0.5)", "seaborn (>=0.9.0)", "memory-profiler (>=0.57.0)", "sphinx (>=4.0.1)", "sphinx-gallery (>=0.7.0)", "numpydoc (>=1.2.0)", "Pillow (>=7.1.2)", "sphinx-prompt (>=1.3.0)", "sphinxext-opengraph (>=0.4.2)"] +examples = ["matplotlib (>=3.1.2)", "scikit-image (>=0.16.2)", "pandas (>=1.0.5)", "seaborn (>=0.9.0)"] +tests = ["matplotlib (>=3.1.2)", "scikit-image (>=0.16.2)", "pandas (>=1.0.5)", "pytest (>=5.0.1)", "pytest-cov (>=2.9.0)", "flake8 (>=3.8.2)", "black (>=22.3.0)", "mypy (>=0.961)", "pyamg (>=4.0.0)", "numpydoc (>=1.2.0)"] [[package]] name = "scipy" @@ -1867,9 +1866,9 @@ python-versions = ">=3.8" numpy = ">=1.18.5,<1.26.0" [package.extras] -dev = ["flake8", "mypy", "pycodestyle", "typing_extensions"] -doc = ["matplotlib (>2)", "numpydoc", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-panels (>=0.5.2)", "sphinx-tabs"] -test = ["asv", "gmpy2", "mpmath", "pytest", "pytest-cov", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] +test = ["pytest", "pytest-cov", "pytest-xdist", "asv", "mpmath", "gmpy2", "threadpoolctl", "scikit-umfpack"] +doc = ["sphinx (!=4.1.0)", "pydata-sphinx-theme (==0.9.0)", "sphinx-panels (>=0.5.2)", "matplotlib (>2)", "numpydoc", "sphinx-tabs"] +dev = ["mypy", "typing-extensions", "pycodestyle", "flake8"] [[package]] name = "send2trash" @@ -1880,23 +1879,10 @@ optional = false python-versions = "*" [package.extras] -nativelib = ["pyobjc-framework-Cocoa", "pywin32"] -objc = ["pyobjc-framework-Cocoa"] +nativelib = ["pyobjc-framework-cocoa", "pywin32"] +objc = ["pyobjc-framework-cocoa"] win32 = ["pywin32"] -[[package]] -name = "setuptools" -version = "65.5.0" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mock", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] - [[package]] name = "setuptools-scm" version = "7.0.5" @@ -1907,7 +1893,6 @@ python-versions = ">=3.7" [package.dependencies] packaging = ">=20.0" -setuptools = "*" tomli = ">=1.0.0" typing-extensions = "*" @@ -1983,8 +1968,8 @@ sphinxcontrib-serializinghtml = ">=1.1.5" [package.extras] docs = ["sphinxcontrib-websupport"] -lint = ["docutils-stubs", "flake8 (>=3.5.0)", "isort", "mypy (>=0.931)", "types-requests", "types-typed-ast"] -test = ["cython", "html5lib", "pytest", "pytest-cov", "typed-ast"] +lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.931)", "docutils-stubs", "types-typed-ast", "types-requests"] +test = ["pytest", "pytest-cov", "html5lib", "cython", "typed-ast"] [[package]] name = "sphinx-autodoc-typehints" @@ -1999,7 +1984,7 @@ Sphinx = ">=4.5" [package.extras] testing = ["covdefaults (>=2.2)", "coverage (>=6.3)", "diff-cover (>=6.4)", "nptyping (>=2.1.2)", "pytest (>=7.1)", "pytest-cov (>=3)", "sphobjinv (>=2)", "typing-extensions (>=4.1)"] -type-comments = ["typed-ast (>=1.5.2)"] +type_comments = ["typed-ast (>=1.5.2)"] [[package]] name = "sphinx-book-theme" @@ -2015,9 +2000,9 @@ pyyaml = "*" sphinx = ">=3,<5" [package.extras] -code-style = ["pre-commit (>=2.7.0,<2.8.0)"] -doc = ["ablog (>=0.10.13,<0.11.0)", "folium", "ipywidgets", "matplotlib", "myst-nb (>=0.13.2,<0.14.0)", "nbclient", "numpy", "numpydoc", "pandas", "plotly", "sphinx (>=4.0,<5.0)", "sphinx-copybutton", "sphinx-design", "sphinx-examples", "sphinx-tabs", "sphinx-thebe (>=0.1.1)", "sphinx-togglebutton (>=0.2.1)", "sphinxcontrib-bibtex (>=2.2,<3.0)", "sphinxcontrib-youtube", "sphinxext-opengraph"] -test = ["beautifulsoup4 (>=4.6.1,<5)", "coverage", "myst-nb (>=0.13.2,<0.14.0)", "pytest (>=6.0.1,<6.1.0)", "pytest-cov", "pytest-regressions (>=2.0.1,<2.1.0)", "sphinx_thebe"] +test = ["sphinx-thebe", "pytest-regressions (>=2.0.1,<2.1.0)", "pytest-cov", "pytest (>=6.0.1,<6.1.0)", "myst-nb (>=0.13.2,<0.14.0)", "coverage", "beautifulsoup4 (>=4.6.1,<5)"] +doc = ["sphinxext-opengraph", "sphinxcontrib-youtube", "sphinxcontrib-bibtex (>=2.2,<3.0)", "sphinx-thebe (>=0.1.1)", "sphinx-togglebutton (>=0.2.1)", "sphinx-tabs", "sphinx-copybutton", "sphinx-examples", "sphinx-design", "sphinx (>=4.0,<5.0)", "plotly", "pandas", "nbclient", "myst-nb (>=0.13.2,<0.14.0)", "numpydoc", "matplotlib", "numpy", "folium", "ipywidgets", "ablog (>=0.10.13,<0.11.0)"] +code_style = ["pre-commit (>=2.7.0,<2.8.0)"] [[package]] name = "sphinx-comments" @@ -2031,9 +2016,9 @@ python-versions = "*" sphinx = ">=1.8" [package.extras] -code-style = ["black", "flake8 (>=3.7.0,<3.8.0)", "pre-commit (==1.17.0)"] -sphinx = ["myst-parser", "sphinx (>=2)", "sphinx-book-theme"] -testing = ["beautifulsoup4", "myst-parser", "pytest", "pytest-regressions", "sphinx (>=2)", "sphinx-book-theme"] +testing = ["sphinx-book-theme", "sphinx (>=2)", "pytest-regressions", "pytest", "myst-parser", "beautifulsoup4"] +sphinx = ["myst-parser", "sphinx-book-theme", "sphinx (>=2)"] +code_style = ["pre-commit (==1.17.0)", "black", "flake8 (>=3.7.0,<3.8.0)"] [[package]] name = "sphinx-copybutton" @@ -2047,8 +2032,8 @@ python-versions = ">=3.6" sphinx = ">=1.8" [package.extras] -code-style = ["pre-commit (==2.12.1)"] -rtd = ["ipython", "myst-nb", "sphinx", "sphinx-book-theme"] +rtd = ["sphinx-book-theme", "myst-nb", "ipython", "sphinx"] +code_style = ["pre-commit (==2.12.1)"] [[package]] name = "sphinx-design" @@ -2062,13 +2047,13 @@ python-versions = ">=3.7" sphinx = ">=3,<5" [package.extras] -code-style = ["pre-commit (>=2.12,<3.0)"] +theme_sbt = ["sphinx-book-theme (>=0.3.0,<0.4.0)"] +theme_rtd = ["sphinx-rtd-theme (>=1.0,<2.0)"] +theme_pydata = ["pydata-sphinx-theme (>=0.8.1,<0.9.0)"] +theme_furo = ["furo (==2022.04.07)"] +testing = ["pytest-regressions", "pytest-cov", "pytest (>=6.2,<7.0)", "myst-parser (>=0.17.0,<0.18.0)"] rtd = ["myst-parser (>=0.17.0,<0.18.0)"] -testing = ["myst-parser (>=0.17.0,<0.18.0)", "pytest (>=6.2,<7.0)", "pytest-cov", "pytest-regressions"] -theme-furo = ["furo (==2022.04.07)"] -theme-pydata = ["pydata-sphinx-theme (>=0.8.1,<0.9.0)"] -theme-rtd = ["sphinx-rtd-theme (>=1.0,<2.0)"] -theme-sbt = ["sphinx-book-theme (>=0.3.0,<0.4.0)"] +code_style = ["pre-commit (>=2.12,<3.0)"] [[package]] name = "sphinx-external-toc" @@ -2085,9 +2070,9 @@ pyyaml = "*" sphinx = ">=3,<5" [package.extras] -code-style = ["pre-commit (>=2.12,<3.0)"] -rtd = ["myst-parser (>=0.15.0,<0.16.0)", "sphinx-book-theme (>=0.0.36)"] -testing = ["coverage", "pytest (>=3.6,<4)", "pytest-cov", "pytest-regressions"] +testing = ["pytest-regressions", "pytest-cov", "pytest (>=3.6,<4)", "coverage"] +rtd = ["sphinx-book-theme (>=0.0.36)", "myst-parser (>=0.15.0,<0.16.0)"] +code_style = ["pre-commit (>=2.12,<3.0)"] [[package]] name = "sphinx-jupyterbook-latex" @@ -2101,7 +2086,7 @@ python-versions = ">=3.6" sphinx = ">=3,<5" [package.extras] -code-style = ["pre-commit (>=2.12,<3.0)"] +code_style = ["pre-commit (>=2.12,<3.0)"] myst = ["myst-nb (>=0.13,<0.14)"] rtd = ["myst-parser", "sphinx-book-theme", "sphinx-design", "sphinx-jupyterbook-latex"] testing = ["coverage (<5.0)", "myst-nb (>=0.13,<0.14)", "pytest (>=3.6,<4)", "pytest-cov (>=2.8,<3.0)", "pytest-regressions", "sphinx-external-toc (>=0.1.0,<0.3.0)", "sphinxcontrib-bibtex (>=2.2.1,<2.3.0)", "texsoup"] @@ -2118,9 +2103,9 @@ python-versions = "*" sphinx = ">=3" [package.extras] -code-style = ["black", "flake8 (>=3.7.0,<3.8.0)", "pre-commit (==1.17.0)"] -rtd = ["myst-parser", "sphinx (>=3.0)", "sphinx-book-theme"] -testing = ["coverage (<5.0)", "jupyter-book", "pytest (>=5.4,<6.0)", "pytest-cov (>=2.8,<3.0)", "pytest-regressions"] +testing = ["jupyter-book", "pytest-regressions", "coverage (<5.0)", "pytest-cov (>=2.8,<3.0)", "pytest (>=5.4,<6.0)"] +rtd = ["myst-parser", "sphinx-book-theme", "sphinx (>=3.0)"] +code_style = ["pre-commit (==1.17.0)", "black", "flake8 (>=3.7.0,<3.8.0)"] [[package]] name = "sphinx-thebe" @@ -2134,8 +2119,8 @@ python-versions = "*" sphinx = ">=3.5,<5" [package.extras] -sphinx = ["matplotlib", "myst-nb", "sphinx-book-theme", "sphinx-copybutton", "sphinx-panels"] -testing = ["beautifulsoup4", "matplotlib", "pytest", "pytest-regressions"] +testing = ["beautifulsoup4", "pytest-regressions", "pytest", "matplotlib"] +sphinx = ["sphinx-panels", "sphinx-copybutton", "sphinx-book-theme", "myst-nb", "matplotlib"] [[package]] name = "sphinx-togglebutton" @@ -2147,12 +2132,10 @@ python-versions = "*" [package.dependencies] docutils = "*" -setuptools = "*" sphinx = "*" -wheel = "*" [package.extras] -sphinx = ["matplotlib", "myst-nb", "numpy", "sphinx-book-theme", "sphinx-design", "sphinx-examples"] +sphinx = ["sphinx-examples", "sphinx-design", "sphinx-book-theme", "myst-nb", "numpy", "matplotlib"] [[package]] name = "sphinxcontrib-applehelp" @@ -2163,8 +2146,8 @@ optional = false python-versions = ">=3.5" [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] test = ["pytest"] +lint = ["docutils-stubs", "mypy", "flake8"] [[package]] name = "sphinxcontrib-bibtex" @@ -2189,8 +2172,8 @@ optional = false python-versions = ">=3.5" [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] test = ["pytest"] +lint = ["docutils-stubs", "mypy", "flake8"] [[package]] name = "sphinxcontrib-htmlhelp" @@ -2201,8 +2184,8 @@ optional = false python-versions = ">=3.6" [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] test = ["html5lib", "pytest"] +lint = ["docutils-stubs", "mypy", "flake8"] [[package]] name = "sphinxcontrib-jsmath" @@ -2213,7 +2196,7 @@ optional = false python-versions = ">=3.5" [package.extras] -test = ["flake8", "mypy", "pytest"] +test = ["mypy", "flake8", "pytest"] [[package]] name = "sphinxcontrib-qthelp" @@ -2224,8 +2207,8 @@ optional = false python-versions = ">=3.5" [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] test = ["pytest"] +lint = ["docutils-stubs", "mypy", "flake8"] [[package]] name = "sphinxcontrib-serializinghtml" @@ -2236,12 +2219,12 @@ optional = false python-versions = ">=3.5" [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] test = ["pytest"] +lint = ["docutils-stubs", "mypy", "flake8"] [[package]] name = "sqlalchemy" -version = "1.4.42" +version = "1.4.43" description = "Database Abstraction Library" category = "dev" optional = false @@ -2251,41 +2234,41 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} [package.extras] -aiomysql = ["aiomysql", "greenlet (!=0.4.17)"] -aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] +aiomysql = ["greenlet (!=0.4.17)", "aiomysql"] +aiosqlite = ["typing_extensions (!=3.10.0.1)", "greenlet (!=0.4.17)", "aiosqlite"] asyncio = ["greenlet (!=0.4.17)"] -asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"] -mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)"] +asyncmy = ["greenlet (!=0.4.17)", "asyncmy (>=0.2.3,!=0.2.4)"] +mariadb_connector = ["mariadb (>=1.0.1,!=1.1.2)"] mssql = ["pyodbc"] -mssql-pymssql = ["pymssql"] -mssql-pyodbc = ["pyodbc"] -mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"] -mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"] -mysql-connector = ["mysql-connector-python"] -oracle = ["cx_oracle (>=7)", "cx_oracle (>=7,<8)"] +mssql_pymssql = ["pymssql"] +mssql_pyodbc = ["pyodbc"] +mypy = ["sqlalchemy2-stubs", "mypy (>=0.910)"] +mysql = ["mysqlclient (>=1.4.0,<2)", "mysqlclient (>=1.4.0)"] +mysql_connector = ["mysql-connector-python"] +oracle = ["cx_oracle (>=7,<8)", "cx_oracle (>=7)"] postgresql = ["psycopg2 (>=2.7)"] -postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] -postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] -postgresql-psycopg2binary = ["psycopg2-binary"] -postgresql-psycopg2cffi = ["psycopg2cffi"] -pymysql = ["pymysql", "pymysql (<1)"] -sqlcipher = ["sqlcipher3_binary"] +postgresql_asyncpg = ["greenlet (!=0.4.17)", "asyncpg"] +postgresql_pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] +postgresql_psycopg2binary = ["psycopg2-binary"] +postgresql_psycopg2cffi = ["psycopg2cffi"] +pymysql = ["pymysql (<1)", "pymysql"] +sqlcipher = ["sqlcipher3-binary"] [[package]] name = "stack-data" -version = "0.5.1" +version = "0.6.0" description = "Extract data from python stack frames and tracebacks for informative displays" category = "dev" optional = false python-versions = "*" [package.dependencies] -asttokens = "*" -executing = "*" +asttokens = ">=2.1.0" +executing = ">=1.2.0" pure-eval = "*" [package.extras] -tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] +tests = ["pytest", "typeguard", "pygments", "littleutils", "cython"] [[package]] name = "starlette" @@ -2314,7 +2297,7 @@ widechars = ["wcwidth"] [[package]] name = "terminado" -version = "0.16.0" +version = "0.17.0" description = "Tornado websocket backend for the Xterm.js Javascript terminal emulator library." category = "dev" optional = false @@ -2326,7 +2309,8 @@ pywinpty = {version = ">=1.1.0", markers = "os_name == \"nt\""} tornado = ">=6.1.0" [package.extras] -test = ["pre-commit", "pytest (>=6.0)", "pytest-timeout"] +docs = ["pydata-sphinx-theme", "sphinx"] +test = ["pre-commit", "pytest-timeout", "pytest (>=7.0)"] [[package]] name = "threadpoolctl" @@ -2348,8 +2332,8 @@ python-versions = ">=3.7" webencodings = ">=0.4" [package.extras] -doc = ["sphinx", "sphinx_rtd_theme"] test = ["flake8", "isort", "pytest"] +doc = ["sphinx-rtd-theme", "sphinx"] [[package]] name = "tokenize-rt" @@ -2413,7 +2397,7 @@ python-versions = "*" [[package]] name = "types-pytz" -version = "2022.5.0.0" +version = "2022.6.0.1" description = "Typing stubs for pytz" category = "dev" optional = false @@ -2448,7 +2432,7 @@ optional = false python-versions = ">=3.6" [package.extras] -test = ["coverage", "pytest", "pytest-cov"] +test = ["pytest-cov", "pytest", "coverage"] [[package]] name = "urllib3" @@ -2459,8 +2443,8 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "urllib3-secure-extra", "ipaddress"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] @@ -2491,19 +2475,19 @@ pandas = "*" [[package]] name = "virtualenv" -version = "20.16.5" +version = "20.16.6" description = "Virtual Python Environment builder" category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] -distlib = ">=0.3.5,<1" +distlib = ">=0.3.6,<1" filelock = ">=3.4.1,<4" platformdirs = ">=2.4,<3" [package.extras] -docs = ["proselint (>=0.13)", "sphinx (>=5.1.1)", "sphinx-argparse (>=0.3.1)", "sphinx-rtd-theme (>=1)", "towncrier (>=21.9)"] +docs = ["proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-argparse (>=0.3.2)", "sphinx-rtd-theme (>=1)", "towncrier (>=22.8)"] testing = ["coverage (>=6.2)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=21.3)", "pytest (>=7.0.1)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.6.1)", "pytest-randomly (>=3.10.3)", "pytest-timeout (>=2.1)"] [[package]] @@ -2524,7 +2508,7 @@ python-versions = "*" [[package]] name = "websocket-client" -version = "1.4.1" +version = "1.4.2" description = "WebSocket client for Python with low level API options" category = "dev" optional = false @@ -2535,17 +2519,6 @@ docs = ["Sphinx (>=3.4)", "sphinx-rtd-theme (>=0.5)"] optional = ["python-socks", "wsaccel"] test = ["websockets"] -[[package]] -name = "wheel" -version = "0.37.1" -description = "A built-package format for Python" -category = "dev" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" - -[package.extras] -test = ["pytest (>=3.0.0)", "pytest-cov"] - [[package]] name = "widgetsnbextension" version = "3.6.1" @@ -2559,1401 +2532,190 @@ notebook = ">=4.4.1" [[package]] name = "zipp" -version = "3.9.0" +version = "3.10.0" description = "Backport of pathlib-compatible object wrapper for zip files" category = "dev" optional = false python-versions = ">=3.7" [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] -testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] +docs = ["sphinx (>=3.5)", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "furo", "jaraco.tidelift (>=1.4)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "flake8 (<5)", "pytest-cov", "pytest-enabler (>=1.3)", "jaraco.itertools", "func-timeout", "jaraco.functools", "more-itertools", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"] [metadata] lock-version = "1.1" python-versions = ">=3.10.0,<3.11" -content-hash = "48f384ffa4501414b93f568a427830002a73fef6fed3ffe7c5cfdec0ad64c505" +content-hash = "e10d169e08d420c3f4637683ad098e6e8f289ab4ec90f14e42dcde9bfe38ed84" [metadata.files] -alabaster = [ - {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"}, - {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, -] -altair = [ - {file = "altair-4.2.0-py3-none-any.whl", hash = "sha256:0c724848ae53410c13fa28be2b3b9a9dcb7b5caa1a70f7f217bd663bb419935a"}, - {file = "altair-4.2.0.tar.gz", hash = "sha256:d87d9372e63b48cd96b2a6415f0cf9457f50162ab79dc7a31cd7e024dd840026"}, -] -anyio = [ - {file = "anyio-3.6.2-py3-none-any.whl", hash = "sha256:fbbe32bd270d2a2ef3ed1c5d45041250284e31fc0a4df4a5a6071842051a51e3"}, - {file = "anyio-3.6.2.tar.gz", hash = "sha256:25ea0d673ae30af41a0c442f81cf3b38c7e79fdc7b60335a4c14e05eb0947421"}, -] -appnope = [ - {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"}, - {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"}, -] -argon2-cffi = [ - {file = "argon2-cffi-21.3.0.tar.gz", hash = "sha256:d384164d944190a7dd7ef22c6aa3ff197da12962bd04b17f64d4e93d934dba5b"}, - {file = "argon2_cffi-21.3.0-py3-none-any.whl", hash = "sha256:8c976986f2c5c0e5000919e6de187906cfd81fb1c72bf9d88c01177e77da7f80"}, -] -argon2-cffi-bindings = [ - {file = "argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f"}, - {file = "argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93"}, - {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194"}, - {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f"}, - {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5"}, - {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351"}, - {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7"}, - {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583"}, - {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d"}, - {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670"}, - {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb"}, - {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a"}, -] -asttokens = [ - {file = "asttokens-2.0.8-py2.py3-none-any.whl", hash = "sha256:e3305297c744ae53ffa032c45dc347286165e4ffce6875dc662b205db0623d86"}, - {file = "asttokens-2.0.8.tar.gz", hash = "sha256:c61e16246ecfb2cde2958406b4c8ebc043c9e6d73aaa83c941673b35e5d3a76b"}, -] +alabaster = [] +altair = [] +anyio = [] +appnope = [] +argon2-cffi = [] +argon2-cffi-bindings = [] +asttokens = [] attrs = [ {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, ] -babel = [ - {file = "Babel-2.10.3-py3-none-any.whl", hash = "sha256:ff56f4892c1c4bf0d814575ea23471c230d544203c7748e8c68f0089478d48eb"}, - {file = "Babel-2.10.3.tar.gz", hash = "sha256:7614553711ee97490f732126dc077f8d0ae084ebc6a96e23db1482afabdb2c51"}, -] -backcall = [ - {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, - {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, -] -beautifulsoup4 = [ - {file = "beautifulsoup4-4.11.1-py3-none-any.whl", hash = "sha256:58d5c3d29f5a36ffeb94f02f0d786cd53014cf9b3b3951d42e0080d8a9498d30"}, - {file = "beautifulsoup4-4.11.1.tar.gz", hash = "sha256:ad9aa55b65ef2808eb405f46cf74df7fcb7044d5cbc26487f96eb2ef2e436693"}, -] -black = [ - {file = "black-22.10.0-1fixedarch-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:5cc42ca67989e9c3cf859e84c2bf014f6633db63d1cbdf8fdb666dcd9e77e3fa"}, - {file = "black-22.10.0-1fixedarch-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:5d8f74030e67087b219b032aa33a919fae8806d49c867846bfacde57f43972ef"}, - {file = "black-22.10.0-1fixedarch-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:197df8509263b0b8614e1df1756b1dd41be6738eed2ba9e9769f3880c2b9d7b6"}, - {file = "black-22.10.0-1fixedarch-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:2644b5d63633702bc2c5f3754b1b475378fbbfb481f62319388235d0cd104c2d"}, - {file = "black-22.10.0-1fixedarch-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:e41a86c6c650bcecc6633ee3180d80a025db041a8e2398dcc059b3afa8382cd4"}, - {file = "black-22.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2039230db3c6c639bd84efe3292ec7b06e9214a2992cd9beb293d639c6402edb"}, - {file = "black-22.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14ff67aec0a47c424bc99b71005202045dc09270da44a27848d534600ac64fc7"}, - {file = "black-22.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:819dc789f4498ecc91438a7de64427c73b45035e2e3680c92e18795a839ebb66"}, - {file = "black-22.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b9b29da4f564ba8787c119f37d174f2b69cdfdf9015b7d8c5c16121ddc054ae"}, - {file = "black-22.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8b49776299fece66bffaafe357d929ca9451450f5466e997a7285ab0fe28e3b"}, - {file = "black-22.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:21199526696b8f09c3997e2b4db8d0b108d801a348414264d2eb8eb2532e540d"}, - {file = "black-22.10.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e464456d24e23d11fced2bc8c47ef66d471f845c7b7a42f3bd77bf3d1789650"}, - {file = "black-22.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9311e99228ae10023300ecac05be5a296f60d2fd10fff31cf5c1fa4ca4b1988d"}, - {file = "black-22.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fba8a281e570adafb79f7755ac8721b6cf1bbf691186a287e990c7929c7692ff"}, - {file = "black-22.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:915ace4ff03fdfff953962fa672d44be269deb2eaf88499a0f8805221bc68c87"}, - {file = "black-22.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:444ebfb4e441254e87bad00c661fe32df9969b2bf224373a448d8aca2132b395"}, - {file = "black-22.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:974308c58d057a651d182208a484ce80a26dac0caef2895836a92dd6ebd725e0"}, - {file = "black-22.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72ef3925f30e12a184889aac03d77d031056860ccae8a1e519f6cbb742736383"}, - {file = "black-22.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:432247333090c8c5366e69627ccb363bc58514ae3e63f7fc75c54b1ea80fa7de"}, - {file = "black-22.10.0-py3-none-any.whl", hash = "sha256:c957b2b4ea88587b46cf49d1dc17681c1e672864fd7af32fc1e9664d572b3458"}, - {file = "black-22.10.0.tar.gz", hash = "sha256:f513588da599943e0cde4e32cc9879e825d58720d6557062d1098c5ad80080e1"}, -] -bleach = [ - {file = "bleach-5.0.1-py3-none-any.whl", hash = "sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a"}, - {file = "bleach-5.0.1.tar.gz", hash = "sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c"}, -] -certifi = [ - {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"}, - {file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"}, -] -cffi = [ - {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, - {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, - {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, - {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, - {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, - {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, - {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, - {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, - {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, - {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, - {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, - {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, - {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, - {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, - {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, - {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, - {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, - {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, - {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, -] +babel = [] +backcall = [] +beautifulsoup4 = [] +black = [] +bleach = [] +certifi = [] +cffi = [] cfgv = [ {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, ] -charset-normalizer = [ - {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, - {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, -] +charset-normalizer = [] click = [ {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, ] -clingo = [ - {file = "clingo-5.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:24fdde61c2f732bf8b1c26fe51bfa86cb6d98503d8a6320f0b88183e5e1b0346"}, - {file = "clingo-5.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:33077c61ff4050ecdcd5b7af00ea5dd057cd8a0e6d3360eeb4197d5be65870b1"}, - {file = "clingo-5.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:714269e2f151ebd4e68de9330ac203013879ae68caf750a1eca749c2428b4958"}, - {file = "clingo-5.6.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e8dfc2e982794bb2870a8144c551a8cfdf77b3537365290a286e218616b6a2d"}, - {file = "clingo-5.6.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:034b6bf0fd2d6517137064efeb79530338ad25c046de2ce8a11d1499defe7548"}, - {file = "clingo-5.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1b1ae9c660af69d5ee513b884a3428dfc5d477f2354aefad016bb14fe969986"}, - {file = "clingo-5.6.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ae375d228aeaf9fdb5f2a0e7f524e43d7e9af15db5d67e0e47e160eafec18a69"}, - {file = "clingo-5.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:524a80793ca5968ab11c35af91bf7226bed390465bc6a0a691d287684945f049"}, - {file = "clingo-5.6.1-cp310-cp310-win32.whl", hash = "sha256:4fa96640e51044be9ede66f6043f248326c6ab65d7d9d02f8b9a80dca2f6558d"}, - {file = "clingo-5.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:8d3ac72892a189082ecfd7a7623e876d6f778c68042d1f3ea7eeeeba03d4e0bc"}, - {file = "clingo-5.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:307ba039678d9c33e213fe55a547ec1b3b1018b3c7fa4d04186ae5812b0c0e75"}, - {file = "clingo-5.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:347172c3eb916a038e3b1a176231b5ea1cbc0db9c4b9a64f1fd4f928fb65cd28"}, - {file = "clingo-5.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcbba5405626198b101eca9b103baec86507b45e21270d8e0a983290932e3099"}, - {file = "clingo-5.6.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f7f248b014d1e6db9f60fd6a501f3d28fd7fb26540ae333b6d8dedd6c324d541"}, - {file = "clingo-5.6.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:82f46f0a17c140539e8d05ea457ed473f25fd37cbd7af73b5d880a5a54442df0"}, - {file = "clingo-5.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da08f73a11e3df86d573e8dbc60a2f141fea7bf1a6153b438adeb7efa911c149"}, - {file = "clingo-5.6.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b14a42b71e2daae26dccc0cae54497f065c9bd97ecb1ec98abcbe37daf8b4c22"}, - {file = "clingo-5.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1be1cf5c99c899b0c32bfb51dc10c3a9e483b6797f5501e740ab8ebf26e896dc"}, - {file = "clingo-5.6.1-cp311-cp311-win32.whl", hash = "sha256:71ff8ba3c96bb4fb36f44b52d79c7320c7f2e40bf95342fe4c81afaa4cb4729b"}, - {file = "clingo-5.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:3f695f74a1f6a132922139c4ab616511d6244d36b43ff5374a84c082d42fea1b"}, - {file = "clingo-5.6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:082defa07fe9fbf4bb5556dd1f7f8b9602a7679ee6bd78f6416b283ed7afa573"}, - {file = "clingo-5.6.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db924e1c1b472eb6bb98caadc49729b8d61ad665f716f9ab977eccf990483c72"}, - {file = "clingo-5.6.1-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c73a0cd2879c09882b61527edae1f0e95bebb8c5aba9ffa32d5a6ac56264f350"}, - {file = "clingo-5.6.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cf31d77490778f07d23113b0a77a298128ffeefd4a67da1f2365c8958e03d020"}, - {file = "clingo-5.6.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfb9e7c0bc0235bbc5029b66a8d0dc68fbb7b43f33f2e55783a8b2d1cb79874f"}, - {file = "clingo-5.6.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:3af97fcd8033437b003667eed7e6c5875535640760c3d9cf69f00b59503bbc01"}, - {file = "clingo-5.6.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:72901ac9f5f6b7c40661050a4266274d6303b0f18d3a9f884ddf47d8b4a9b596"}, - {file = "clingo-5.6.1-cp36-cp36m-win32.whl", hash = "sha256:0ec0af53a15c86f103a84d4707871e9cea25cc4a70c34fd26bfd1cd167f0f6ec"}, - {file = "clingo-5.6.1-cp36-cp36m-win_amd64.whl", hash = "sha256:1f8eaf90ad602b353a414be15c4f2d5c171ae7dd5b1da189d65c9884a4798013"}, - {file = "clingo-5.6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a794e04840a7d99723f7435e92c6121e56d8383dd9d84335e2508725117c97fd"}, - {file = "clingo-5.6.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d660f1b7f6121f61b88d44466e4a0c8fa1f3858c3252ab36c24526702beb604e"}, - {file = "clingo-5.6.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:55bbde279de770e8e909420c2d939dac8d3a74b3a187bc6b9d584dda4b6e712a"}, - {file = "clingo-5.6.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:27932397ab8a15b8ba17c1529064b4ea49c36cfd90a328a4c5b71a3ff8f9e578"}, - {file = "clingo-5.6.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed683dba5199f4d7206bf881d6f4ad258885b8e87bba807cee7f4018ba95f0b1"}, - {file = "clingo-5.6.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:71d4387be23e22bd8a1bb223479624d4aa1474223df6fbdcc2173a78543e18dc"}, - {file = "clingo-5.6.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:1fd1c1d54c9cae4e6fa284ed4a6b39e7c7b1cf1f1e628cf7687c94a94dabb333"}, - {file = "clingo-5.6.1-cp37-cp37m-win32.whl", hash = "sha256:5673ecb543dc82639a8c078a8e5067d1d03fdc39f13460d3ba4dc6792fdad530"}, - {file = "clingo-5.6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:5168259903b23a657b0f50729d9f4d8811f670fecd0e594c1748268b8d5c6732"}, - {file = "clingo-5.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ae39f1f109c514f7957931fdfd43a93060e4f7691953450e2aab4b835cbd1394"}, - {file = "clingo-5.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5ba97e1ae215914202a74529a179f1e8d0d1091174b673dd9cb3b5d0a0cdff65"}, - {file = "clingo-5.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6bc8e2f92f4b81aa32fed9f938642a3033a9a91629e5e38caf9b1c2c3ebba0c"}, - {file = "clingo-5.6.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a362bba14d31d8ccee4f09c089cf54047edd3635c088def7486576a3eeec5628"}, - {file = "clingo-5.6.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c8d65efed7bad08ee0cb405842f8ec6c2bbd2c05ab2633440178bb876f20335"}, - {file = "clingo-5.6.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:078c2fc801a799629d2051115c3108ebbaeddc46b18077446c86eef0aea7edac"}, - {file = "clingo-5.6.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:50a21cb67328b95bc2a32859a948c47328a1b1b91983fb1fc3d10a5014320651"}, - {file = "clingo-5.6.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8a27a4757cf46021262fbeda9d361aa4ffaea69ed29ca6f05f355845a4467795"}, - {file = "clingo-5.6.1-cp38-cp38-win32.whl", hash = "sha256:c2e2c153ecd97edd159eb6ee894d6edbf6ac6e813e41acc29acbfe0ccb4b3df1"}, - {file = "clingo-5.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:26f260b0e1d9902cd5f4274c4e30320a498d7a5006cc13e86064e45045e7f093"}, - {file = "clingo-5.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:78bd14fae47c366d23ac3c78d2494c49b022a9a0005aa699c6107ba6ac19c615"}, - {file = "clingo-5.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:eeaa28f61b24478e245e87256d137aa41af60aac0d94d569c7faf88538459830"}, - {file = "clingo-5.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d114b095333d3475b7cc598b0bd31c80a74d4e8ca5c72dc497632968c81e341"}, - {file = "clingo-5.6.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f14e79a7c794df0fad3f3e6bccf1eaf2d460d45716a422ebad515d473d67531c"}, - {file = "clingo-5.6.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea38413bb4c300d496def33360f99d1964ed6afc7aa300b0b77143544997f6d"}, - {file = "clingo-5.6.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c73bf19808be54d0958397cf6bbeff213089d0280b5da3fdbc031668e23b3ea7"}, - {file = "clingo-5.6.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8a781ee23019e5dec013153528ef0bbab2df3ffcb750be130facec5ef472cc35"}, - {file = "clingo-5.6.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:faaef9539f0f7baa084035f82f11c63dd188b0657ff90610a00dc64ce965bc1d"}, - {file = "clingo-5.6.1-cp39-cp39-win32.whl", hash = "sha256:27ac28d4413a8606f1de11bb38188df5548509308d58ac50c197ed480b4aeefe"}, - {file = "clingo-5.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:3df3c99fa177b0a5f5f67c4d56748bd3c893a1e76dd63b327e7db0de3b97f706"}, - {file = "clingo-5.6.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:297a16e1d9b9232b46cf81445422c9c68dd4468d8ea4c6b42bbf917c118ecdb9"}, - {file = "clingo-5.6.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59a82a40c96554af037e025ccd45982a0c69d7e6297c4645875be7b163f2bee1"}, - {file = "clingo-5.6.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1a997802c90b8501e640aa32dfba1c1cd47579f425779d74ab97db086074d362"}, - {file = "clingo-5.6.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bdb80858c81c982020576afdcd1eeff6fa1d5ac9a86871247b3d43613c6bea2"}, - {file = "clingo-5.6.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c9cfba59876a6e7717761ef12f031a9e3981768034de51db8f66f786f59e4ca0"}, - {file = "clingo-5.6.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f3e6273f698578512ba48039c1b2c41152fe49f6999c1585480016079844318"}, - {file = "clingo-5.6.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:274aabcac16a592cbc67d01c112702d861c2c7f2613d97e03e38e74e7245c759"}, - {file = "clingo-5.6.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d34b3f1e2f2ce4d0ba9adec607187d18737d33f786597bf6758c082df59f5671"}, - {file = "clingo-5.6.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6bc9de138f15cf2e2671335f4c9bb2925da9f1817aad3367b4c1abe4908f022d"}, - {file = "clingo-5.6.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33031c41524e0ef005979739262d8281d6b993174a7975acbefe9ad0d31fe84a"}, - {file = "clingo-5.6.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3493518250146effafefb0f655790b8257acf6723ea144fd3263aa1e1cbd6e"}, - {file = "clingo-5.6.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:862acdb45611222bc286730859aa76cacb9a836d9c9cfe3378d9292dcfb5d4e7"}, - {file = "clingo-5.6.1.tar.gz", hash = "sha256:facdce78bcb30ae161a44e5dfbd811b769c1245ae7a1aaebb15ef90322753c3b"}, -] -colorama = [ - {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, - {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, -] -contourpy = [ - {file = "contourpy-1.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:87121b9428ac568fb84fae4af5e7852fc34f02eadc4e3e91f6c8989327692186"}, - {file = "contourpy-1.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1fb782982c42cee667b892a0b0c52a9f6c7ecf1da5c5f4345845f04eaa862f93"}, - {file = "contourpy-1.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:689d7d2a840619915d0abd1ecc6e399fee202f8ad315acda2807f4ca420d0802"}, - {file = "contourpy-1.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d88814befbd1433152c5f6dd536905149ba028d795a22555b149ae0a36024d9e"}, - {file = "contourpy-1.0.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df65f4b2b4e74977f0336bef12a88051ab24e6a16873cd9249f34d67cb3e345d"}, - {file = "contourpy-1.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6b4c0c723664f65c2a47c8cb6ebbf660b0b2e2d936adf2e8503d4e93359465"}, - {file = "contourpy-1.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bcc98d397c3dea45d5b262029564b29cb8e945f2607a38bee6163694c0a8b4ef"}, - {file = "contourpy-1.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2bf5c846c257578b03d498b20f54f53551616a507d8e5463511c58bb58e9a9cf"}, - {file = "contourpy-1.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdacddb18d55ffec42d1907079cdc04ec4fa8a990cdf5b9d9fe67d281fc0d12e"}, - {file = "contourpy-1.0.5-cp310-cp310-win32.whl", hash = "sha256:434942fa2f9019b9ae525fb752dc523800c49a1a28fbd6d9240b0fa959573dcc"}, - {file = "contourpy-1.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:3b3082ade8849130203d461b98c2a061b382c46074b43b4edd5cefd81af92b8a"}, - {file = "contourpy-1.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:057114f698ffb9e54657e8fda6802e2f5c8fad609845cf6afaf31590ef6a33c0"}, - {file = "contourpy-1.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:218722a29c5c26677d37c44f5f8a372daf6f07870aad793a97d47eb6ad6b3290"}, - {file = "contourpy-1.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6c02e22cf09996194bcb3a4784099975cf527d5c29caf759abadf29ebdb2fe27"}, - {file = "contourpy-1.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0d5ee865b5fd16bf62d72122aadcc90aab296c30c1adb0a32b4b66bd843163e"}, - {file = "contourpy-1.0.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d45822b0a2a452327ab4f95efe368d234d5294bbf89a99968be27c7938a21108"}, - {file = "contourpy-1.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dca5be83a6dfaf933a46e3bc2b9f2685e5ec61b22f6a38ad740aac9c16e9a0ff"}, - {file = "contourpy-1.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3c3f2f6b898a40207843ae01970e57e33d22a26b22f23c6a5e07b4716751085f"}, - {file = "contourpy-1.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c2b4eab7c12f9cb460509bc34a3b086f9802f0dba27c89a63df4123819ad64af"}, - {file = "contourpy-1.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09ed9b63f4df8a7591b7a4a26c1ad066dcaafda1f846250fdcb534074a411692"}, - {file = "contourpy-1.0.5-cp311-cp311-win32.whl", hash = "sha256:f670686d99c867d0f24b28ce8c6f02429c6eef5e2674aab287850d0ee2d20437"}, - {file = "contourpy-1.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:c51568e94f7f232296de30002f2a50f77a7bd346673da3e4f2aaf9d2b833f2e5"}, - {file = "contourpy-1.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7c9e99aac7b430f6a9f15eebf058c742097cea3369f23a2bfc5e64d374b67e3a"}, - {file = "contourpy-1.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3210d93ad2af742b6a96cf39792f7181822edbb8fe11c3ef29d1583fe637a8d8"}, - {file = "contourpy-1.0.5-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:128bd7acf569f8443ad5b2227f30ac909e4f5399ed221727eeacf0c6476187e6"}, - {file = "contourpy-1.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:813c2944e940ef8dccea71305bacc942d4b193a021140874b3e58933ec44f5b6"}, - {file = "contourpy-1.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a74afd8d560eaafe0d9e3e1db8c06081282a05ca4de00ee416195085a79d7d3d"}, - {file = "contourpy-1.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d0ad9a85f208473b1f3613c45756c7aa6fcc288266a8c7b873f896aaf741b6b"}, - {file = "contourpy-1.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:60f37acd4e4227c5a29f737d9a85ca3145c529a8dd4bf70af7f0637c61b49222"}, - {file = "contourpy-1.0.5-cp37-cp37m-win32.whl", hash = "sha256:b50e481a4317a8efcfffcfddcd4c9b36eacba440440e70cbe0256aeb6fd6abae"}, - {file = "contourpy-1.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:0395ae71164bfeb2dedd136e03c71a2718a5aa9873a46f518f4133be0d63e1d2"}, - {file = "contourpy-1.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3ca40d7844b391d90b864c6a6d1bb6b88b09035fb4d866d64d43c4d26fb0ab64"}, - {file = "contourpy-1.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3109fa601d2a448cec4643abd3a31f972bf05b7c2f2e83df9d3429878f8c10ae"}, - {file = "contourpy-1.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:06c4d1dde5ee4f909a8a95ba1eb04040c6c26946b4f3b5beaf10d45f14e940ee"}, - {file = "contourpy-1.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f54dcc9bb9390fd0636301ead134d46d5229fe86da0db4d974c0fda349f560e"}, - {file = "contourpy-1.0.5-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:46b8e24813e2fb5a3e598c1f8b9ae403e1438cb846a80cc2b33cddf19dddd7f2"}, - {file = "contourpy-1.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:061e1f066c419ffe25b615a1df031b4832ea1d7f2676937e69e8e00e24512005"}, - {file = "contourpy-1.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:19ea64fa0cf389d2ebc10974616acfa1fdecbd73d1fd9c72215b782f3c40f561"}, - {file = "contourpy-1.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:dfe924e5a63861c82332a12adeeab955dc8c8009ddbbd80cc2fcca049ff89a49"}, - {file = "contourpy-1.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bed3a2a823a041e8d249b1a7ec132933e1505299329b5cfe1b2b5ec689ec7675"}, - {file = "contourpy-1.0.5-cp38-cp38-win32.whl", hash = "sha256:0389349875424aa8c5e61f757e894687916bc4e9616cc6afcbd8051aa2428952"}, - {file = "contourpy-1.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:2b5e334330d82866923015b455260173cb3b9e3b4e297052d758abd262031289"}, - {file = "contourpy-1.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:def9a01b73c9e27d70ea03b381fb3e7aadfac1f398dbd63751313c3a46747ef5"}, - {file = "contourpy-1.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:59c827e536bb5e3ef58e06da0faba61fd89a14f30b68bcfeca41f43ca83a1942"}, - {file = "contourpy-1.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f05d311c937da03b0cd26ac3e14cb991f6ff8fc94f98b3df9713537817539795"}, - {file = "contourpy-1.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:970a4be7ec84ccda7c27cb4ae74930bbbd477bc8d849ed55ea798084dd5fca8c"}, - {file = "contourpy-1.0.5-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f7672148f8fca48e4efc16aba24a7455b40c22d4f8abe42475dec6a12b0bb9a"}, - {file = "contourpy-1.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eba62b7c21a33e72dd8adab2b92dd5610d8527f0b2ac28a8e0770e71b21a13f9"}, - {file = "contourpy-1.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:dd084459ecdb224e617e4ab3f1d5ebe4d1c48facb41f24952b76aa6ba9712bb0"}, - {file = "contourpy-1.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c5158616ab39d34b76c50f40c81552ee180598f7825dc7a66fd187d29958820f"}, - {file = "contourpy-1.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f856652f9b533c6cd2b9ad6836a7fc0e43917d7ff15be46c5baf1350f8cdc5d9"}, - {file = "contourpy-1.0.5-cp39-cp39-win32.whl", hash = "sha256:f1cc623fd6855b25da52b3275e0c9e51711b86a9dccc75f8c9ab4432fd8e42c7"}, - {file = "contourpy-1.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:e67dcaa34dcd908fcccbf49194211d847c731b6ebaac661c1c889f1bf6af1e44"}, - {file = "contourpy-1.0.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bfd634cb9685161b2a51f73a7fc4736fd0d67a56632d52319317afaa27f08243"}, - {file = "contourpy-1.0.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79908b9d02b1d6c1c71ff3b7ad127f3f82e14a8e091ab44b3c7e34b649fea733"}, - {file = "contourpy-1.0.5-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4963cf08f4320d98ae72ec7694291b8ab85cb7da3b0cd824bc32701bc992edf"}, - {file = "contourpy-1.0.5-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cfc067ddde78b76dcbc9684d82688b7d3c5158fa2254a085f9bcb9586c1e2d8"}, - {file = "contourpy-1.0.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:9939796abcadb2810a63dfb26ff8ca4595fe7dd70a3ceae7f607a2639b714307"}, - {file = "contourpy-1.0.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d8150579bf30cdf896906baf256aa200cd50dbe6e565c17d6fd3d678e21ff5de"}, - {file = "contourpy-1.0.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed9c91bf4ce614efed5388c3f989a7cfe08728ab871d995a486ea74ff88993db"}, - {file = "contourpy-1.0.5-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b46a04588ceb7cf132568e0e564a854627ef87a1ed3bf536234540a79ced44b0"}, - {file = "contourpy-1.0.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b85553699862c09937a7a5ea14ee6229087971a7d51ae97d5f4b407f571a2c17"}, - {file = "contourpy-1.0.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:99a8071e351b50827ad976b92ed91845fb614ac67a3c41109b24f3d8bd3afada"}, - {file = "contourpy-1.0.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fb0458d74726937ead9e2effc91144aea5a58ecee9754242f8539a782bed685a"}, - {file = "contourpy-1.0.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f89f0608a5aa8142ed0e53957916623791a88c7f5e5f07ae530c328beeb888f"}, - {file = "contourpy-1.0.5-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce763369e646e59e4ca2c09735cd1bdd3048d909ad5f2bc116e83166a9352f3c"}, - {file = "contourpy-1.0.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c16fa267740d67883899e054cccb4279e002f3f4872873b752c1ba15045ff49"}, - {file = "contourpy-1.0.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a30e95274f5c0e007ccc759ec258aa5708c534ec058f153ee25ac700a2f1438b"}, - {file = "contourpy-1.0.5.tar.gz", hash = "sha256:896631cd40222aef3697e4e51177d14c3709fda49d30983269d584f034acc8a4"}, -] -coverage = [ - {file = "coverage-6.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef8674b0ee8cc11e2d574e3e2998aea5df5ab242e012286824ea3c6970580e53"}, - {file = "coverage-6.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:784f53ebc9f3fd0e2a3f6a78b2be1bd1f5575d7863e10c6e12504f240fd06660"}, - {file = "coverage-6.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4a5be1748d538a710f87542f22c2cad22f80545a847ad91ce45e77417293eb4"}, - {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83516205e254a0cb77d2d7bb3632ee019d93d9f4005de31dca0a8c3667d5bc04"}, - {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af4fffaffc4067232253715065e30c5a7ec6faac36f8fc8d6f64263b15f74db0"}, - {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:97117225cdd992a9c2a5515db1f66b59db634f59d0679ca1fa3fe8da32749cae"}, - {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a1170fa54185845505fbfa672f1c1ab175446c887cce8212c44149581cf2d466"}, - {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:11b990d520ea75e7ee8dcab5bc908072aaada194a794db9f6d7d5cfd19661e5a"}, - {file = "coverage-6.5.0-cp310-cp310-win32.whl", hash = "sha256:5dbec3b9095749390c09ab7c89d314727f18800060d8d24e87f01fb9cfb40b32"}, - {file = "coverage-6.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:59f53f1dc5b656cafb1badd0feb428c1e7bc19b867479ff72f7a9dd9b479f10e"}, - {file = "coverage-6.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4a5375e28c5191ac38cca59b38edd33ef4cc914732c916f2929029b4bfb50795"}, - {file = "coverage-6.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ed2820d919351f4167e52425e096af41bfabacb1857186c1ea32ff9983ed75"}, - {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33a7da4376d5977fbf0a8ed91c4dffaaa8dbf0ddbf4c8eea500a2486d8bc4d7b"}, - {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fb6cf131ac4070c9c5a3e21de0f7dc5a0fbe8bc77c9456ced896c12fcdad91"}, - {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a6b7d95969b8845250586f269e81e5dfdd8ff828ddeb8567a4a2eaa7313460c4"}, - {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1ef221513e6f68b69ee9e159506d583d31aa3567e0ae84eaad9d6ec1107dddaa"}, - {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cca4435eebea7962a52bdb216dec27215d0df64cf27fc1dd538415f5d2b9da6b"}, - {file = "coverage-6.5.0-cp311-cp311-win32.whl", hash = "sha256:98e8a10b7a314f454d9eff4216a9a94d143a7ee65018dd12442e898ee2310578"}, - {file = "coverage-6.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:bc8ef5e043a2af066fa8cbfc6e708d58017024dc4345a1f9757b329a249f041b"}, - {file = "coverage-6.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4433b90fae13f86fafff0b326453dd42fc9a639a0d9e4eec4d366436d1a41b6d"}, - {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4f05d88d9a80ad3cac6244d36dd89a3c00abc16371769f1340101d3cb899fc3"}, - {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94e2565443291bd778421856bc975d351738963071e9b8839ca1fc08b42d4bef"}, - {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:027018943386e7b942fa832372ebc120155fd970837489896099f5cfa2890f79"}, - {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:255758a1e3b61db372ec2736c8e2a1fdfaf563977eedbdf131de003ca5779b7d"}, - {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:851cf4ff24062c6aec510a454b2584f6e998cada52d4cb58c5e233d07172e50c"}, - {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:12adf310e4aafddc58afdb04d686795f33f4d7a6fa67a7a9d4ce7d6ae24d949f"}, - {file = "coverage-6.5.0-cp37-cp37m-win32.whl", hash = "sha256:b5604380f3415ba69de87a289a2b56687faa4fe04dbee0754bfcae433489316b"}, - {file = "coverage-6.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4a8dbc1f0fbb2ae3de73eb0bdbb914180c7abfbf258e90b311dcd4f585d44bd2"}, - {file = "coverage-6.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d900bb429fdfd7f511f868cedd03a6bbb142f3f9118c09b99ef8dc9bf9643c3c"}, - {file = "coverage-6.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2198ea6fc548de52adc826f62cb18554caedfb1d26548c1b7c88d8f7faa8f6ba"}, - {file = "coverage-6.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c4459b3de97b75e3bd6b7d4b7f0db13f17f504f3d13e2a7c623786289dd670e"}, - {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:20c8ac5386253717e5ccc827caad43ed66fea0efe255727b1053a8154d952398"}, - {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b07130585d54fe8dff3d97b93b0e20290de974dc8177c320aeaf23459219c0b"}, - {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dbdb91cd8c048c2b09eb17713b0c12a54fbd587d79adcebad543bc0cd9a3410b"}, - {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:de3001a203182842a4630e7b8d1a2c7c07ec1b45d3084a83d5d227a3806f530f"}, - {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e07f4a4a9b41583d6eabec04f8b68076ab3cd44c20bd29332c6572dda36f372e"}, - {file = "coverage-6.5.0-cp38-cp38-win32.whl", hash = "sha256:6d4817234349a80dbf03640cec6109cd90cba068330703fa65ddf56b60223a6d"}, - {file = "coverage-6.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:7ccf362abd726b0410bf8911c31fbf97f09f8f1061f8c1cf03dfc4b6372848f6"}, - {file = "coverage-6.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:633713d70ad6bfc49b34ead4060531658dc6dfc9b3eb7d8a716d5873377ab745"}, - {file = "coverage-6.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:95203854f974e07af96358c0b261f1048d8e1083f2de9b1c565e1be4a3a48cfc"}, - {file = "coverage-6.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9023e237f4c02ff739581ef35969c3739445fb059b060ca51771e69101efffe"}, - {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:265de0fa6778d07de30bcf4d9dc471c3dc4314a23a3c6603d356a3c9abc2dfcf"}, - {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f830ed581b45b82451a40faabb89c84e1a998124ee4212d440e9c6cf70083e5"}, - {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7b6be138d61e458e18d8e6ddcddd36dd96215edfe5f1168de0b1b32635839b62"}, - {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:42eafe6778551cf006a7c43153af1211c3aaab658d4d66fa5fcc021613d02518"}, - {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:723e8130d4ecc8f56e9a611e73b31219595baa3bb252d539206f7bbbab6ffc1f"}, - {file = "coverage-6.5.0-cp39-cp39-win32.whl", hash = "sha256:d9ecf0829c6a62b9b573c7bb6d4dcd6ba8b6f80be9ba4fc7ed50bf4ac9aecd72"}, - {file = "coverage-6.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:fc2af30ed0d5ae0b1abdb4ebdce598eafd5b35397d4d75deb341a614d333d987"}, - {file = "coverage-6.5.0-pp36.pp37.pp38-none-any.whl", hash = "sha256:1431986dac3923c5945271f169f59c45b8802a114c8f548d611f2015133df77a"}, - {file = "coverage-6.5.0.tar.gz", hash = "sha256:f642e90754ee3e06b0e7e51bce3379590e76b7f76b708e1a71ff043f87025c84"}, -] -cycler = [ - {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, - {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, -] -debugpy = [ - {file = "debugpy-1.6.3-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:c4b2bd5c245eeb49824bf7e539f95fb17f9a756186e51c3e513e32999d8846f3"}, - {file = "debugpy-1.6.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b8deaeb779699350deeed835322730a3efec170b88927debc9ba07a1a38e2585"}, - {file = "debugpy-1.6.3-cp310-cp310-win32.whl", hash = "sha256:fc233a0160f3b117b20216f1169e7211b83235e3cd6749bcdd8dbb72177030c7"}, - {file = "debugpy-1.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:dda8652520eae3945833e061cbe2993ad94a0b545aebd62e4e6b80ee616c76b2"}, - {file = "debugpy-1.6.3-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:d5c814596a170a0a58fa6fad74947e30bfd7e192a5d2d7bd6a12156c2899e13a"}, - {file = "debugpy-1.6.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c4cd6f37e3c168080d61d698390dfe2cd9e74ebf80b448069822a15dadcda57d"}, - {file = "debugpy-1.6.3-cp37-cp37m-win32.whl", hash = "sha256:3c9f985944a30cfc9ae4306ac6a27b9c31dba72ca943214dad4a0ab3840f6161"}, - {file = "debugpy-1.6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:5ad571a36cec137ae6ed951d0ff75b5e092e9af6683da084753231150cbc5b25"}, - {file = "debugpy-1.6.3-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:adcfea5ea06d55d505375995e150c06445e2b20cd12885bcae566148c076636b"}, - {file = "debugpy-1.6.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:daadab4403427abd090eccb38d8901afd8b393e01fd243048fab3f1d7132abb4"}, - {file = "debugpy-1.6.3-cp38-cp38-win32.whl", hash = "sha256:6efc30325b68e451118b795eff6fe8488253ca3958251d5158106d9c87581bc6"}, - {file = "debugpy-1.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:86d784b72c5411c833af1cd45b83d80c252b77c3bfdb43db17c441d772f4c734"}, - {file = "debugpy-1.6.3-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:4e255982552b0edfe3a6264438dbd62d404baa6556a81a88f9420d3ed79b06ae"}, - {file = "debugpy-1.6.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cca23cb6161ac89698d629d892520327dd1be9321c0960e610bbcb807232b45d"}, - {file = "debugpy-1.6.3-cp39-cp39-win32.whl", hash = "sha256:7c302095a81be0d5c19f6529b600bac971440db3e226dce85347cc27e6a61908"}, - {file = "debugpy-1.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:34d2cdd3a7c87302ba5322b86e79c32c2115be396f3f09ca13306d8a04fe0f16"}, - {file = "debugpy-1.6.3-py2.py3-none-any.whl", hash = "sha256:84c39940a0cac410bf6aa4db00ba174f973eef521fbe9dd058e26bcabad89c4f"}, - {file = "debugpy-1.6.3.zip", hash = "sha256:e8922090514a890eec99cfb991bab872dd2e353ebb793164d5f01c362b9a40bf"}, -] -decorator = [ - {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, - {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, -] -defusedxml = [ - {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, - {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, -] -distlib = [ - {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"}, - {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, -] -docutils = [ - {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"}, - {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"}, -] -entrypoints = [ - {file = "entrypoints-0.4-py3-none-any.whl", hash = "sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f"}, - {file = "entrypoints-0.4.tar.gz", hash = "sha256:b706eddaa9218a19ebcd67b56818f05bb27589b1ca9e8d797b74affad4ccacd4"}, -] -exceptiongroup = [ - {file = "exceptiongroup-1.0.0-py3-none-any.whl", hash = "sha256:2ac84b496be68464a2da60da518af3785fff8b7ec0d090a581604bc870bdee41"}, - {file = "exceptiongroup-1.0.0.tar.gz", hash = "sha256:affbabf13fb6e98988c38d9c5650e701569fe3c1de3233cfb61c5f33774690ad"}, -] -executing = [ - {file = "executing-1.1.1-py2.py3-none-any.whl", hash = "sha256:236ea5f059a38781714a8bfba46a70fad3479c2f552abee3bbafadc57ed111b8"}, - {file = "executing-1.1.1.tar.gz", hash = "sha256:b0d7f8dcc2bac47ce6e39374397e7acecea6fdc380a6d5323e26185d70f38ea8"}, -] -fastapi = [ - {file = "fastapi-0.85.1-py3-none-any.whl", hash = "sha256:de3166b6b1163dc22da4dc4ebdc3192fcbac7700dd1870a1afa44de636a636b5"}, - {file = "fastapi-0.85.1.tar.gz", hash = "sha256:1facd097189682a4ff11cbd01334a992e51b56be663b2bd50c2c09523624f144"}, -] -fastjsonschema = [ - {file = "fastjsonschema-2.16.2-py3-none-any.whl", hash = "sha256:21f918e8d9a1a4ba9c22e09574ba72267a6762d47822db9add95f6454e51cc1c"}, - {file = "fastjsonschema-2.16.2.tar.gz", hash = "sha256:01e366f25d9047816fe3d288cbfc3e10541daf0af2044763f3d0ade42476da18"}, -] -filelock = [ - {file = "filelock-3.8.0-py3-none-any.whl", hash = "sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4"}, - {file = "filelock-3.8.0.tar.gz", hash = "sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc"}, -] -flake8 = [ - {file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"}, - {file = "flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db"}, -] -flake8-black = [ - {file = "flake8-black-0.3.3.tar.gz", hash = "sha256:8211f5e20e954cb57c709acccf2f3281ce27016d4c4b989c3e51f878bb7ce12a"}, - {file = "flake8_black-0.3.3-py3-none-any.whl", hash = "sha256:7d667d0059fd1aa468de1669d77cc934b7f1feeac258d57bdae69a8e73c4cd90"}, -] -fonttools = [ - {file = "fonttools-4.37.4-py3-none-any.whl", hash = "sha256:afae1b39555f9c3f0ad1f0f1daf678e5ad157e38c8842ecb567951bf1a9b9fd7"}, - {file = "fonttools-4.37.4.zip", hash = "sha256:86918c150c6412798e15a0de6c3e0d061ddefddd00f97b4f7b43dfa867ad315e"}, -] -gitdb = [ - {file = "gitdb-4.0.9-py3-none-any.whl", hash = "sha256:8033ad4e853066ba6ca92050b9df2f89301b8fc8bf7e9324d412a63f8bf1a8fd"}, - {file = "gitdb-4.0.9.tar.gz", hash = "sha256:bac2fd45c0a1c9cf619e63a90d62bdc63892ef92387424b855792a6cabe789aa"}, -] -gitpython = [ - {file = "GitPython-3.1.29-py3-none-any.whl", hash = "sha256:41eea0deec2deea139b459ac03656f0dd28fc4a3387240ec1d3c259a2c47850f"}, - {file = "GitPython-3.1.29.tar.gz", hash = "sha256:cc36bfc4a3f913e66805a28e84703e419d9c264c1077e537b54f0e1af85dbefd"}, -] -greenlet = [ - {file = "greenlet-1.1.3.post0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:949c9061b8c6d3e6e439466a9be1e787208dec6246f4ec5fffe9677b4c19fcc3"}, - {file = "greenlet-1.1.3.post0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:d7815e1519a8361c5ea2a7a5864945906f8e386fa1bc26797b4d443ab11a4589"}, - {file = "greenlet-1.1.3.post0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:9649891ab4153f217f319914455ccf0b86986b55fc0573ce803eb998ad7d6854"}, - {file = "greenlet-1.1.3.post0-cp27-cp27m-win32.whl", hash = "sha256:11fc7692d95cc7a6a8447bb160d98671ab291e0a8ea90572d582d57361360f05"}, - {file = "greenlet-1.1.3.post0-cp27-cp27m-win_amd64.whl", hash = "sha256:05ae7383f968bba4211b1fbfc90158f8e3da86804878442b4fb6c16ccbcaa519"}, - {file = "greenlet-1.1.3.post0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ccbe7129a282ec5797df0451ca1802f11578be018a32979131065565da89b392"}, - {file = "greenlet-1.1.3.post0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:4a8b58232f5b72973350c2b917ea3df0bebd07c3c82a0a0e34775fc2c1f857e9"}, - {file = "greenlet-1.1.3.post0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:f6661b58412879a2aa099abb26d3c93e91dedaba55a6394d1fb1512a77e85de9"}, - {file = "greenlet-1.1.3.post0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c6e942ca9835c0b97814d14f78da453241837419e0d26f7403058e8db3e38f8"}, - {file = "greenlet-1.1.3.post0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a812df7282a8fc717eafd487fccc5ba40ea83bb5b13eb3c90c446d88dbdfd2be"}, - {file = "greenlet-1.1.3.post0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83a7a6560df073ec9de2b7cb685b199dfd12519bc0020c62db9d1bb522f989fa"}, - {file = "greenlet-1.1.3.post0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:17a69967561269b691747e7f436d75a4def47e5efcbc3c573180fc828e176d80"}, - {file = "greenlet-1.1.3.post0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:60839ab4ea7de6139a3be35b77e22e0398c270020050458b3d25db4c7c394df5"}, - {file = "greenlet-1.1.3.post0-cp310-cp310-win_amd64.whl", hash = "sha256:8926a78192b8b73c936f3e87929931455a6a6c6c385448a07b9f7d1072c19ff3"}, - {file = "greenlet-1.1.3.post0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:c6f90234e4438062d6d09f7d667f79edcc7c5e354ba3a145ff98176f974b8132"}, - {file = "greenlet-1.1.3.post0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:814f26b864ed2230d3a7efe0336f5766ad012f94aad6ba43a7c54ca88dd77cba"}, - {file = "greenlet-1.1.3.post0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8fda1139d87ce5f7bd80e80e54f9f2c6fe2f47983f1a6f128c47bf310197deb6"}, - {file = "greenlet-1.1.3.post0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0643250dd0756f4960633f5359884f609a234d4066686754e834073d84e9b51"}, - {file = "greenlet-1.1.3.post0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cb863057bed786f6622982fb8b2c122c68e6e9eddccaa9fa98fd937e45ee6c4f"}, - {file = "greenlet-1.1.3.post0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8c0581077cf2734569f3e500fab09c0ff6a2ab99b1afcacbad09b3c2843ae743"}, - {file = "greenlet-1.1.3.post0-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:695d0d8b5ae42c800f1763c9fce9d7b94ae3b878919379150ee5ba458a460d57"}, - {file = "greenlet-1.1.3.post0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:5662492df0588a51d5690f6578f3bbbd803e7f8d99a99f3bf6128a401be9c269"}, - {file = "greenlet-1.1.3.post0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:bffba15cff4802ff493d6edcf20d7f94ab1c2aee7cfc1e1c7627c05f1102eee8"}, - {file = "greenlet-1.1.3.post0-cp35-cp35m-win32.whl", hash = "sha256:7afa706510ab079fd6d039cc6e369d4535a48e202d042c32e2097f030a16450f"}, - {file = "greenlet-1.1.3.post0-cp35-cp35m-win_amd64.whl", hash = "sha256:3a24f3213579dc8459e485e333330a921f579543a5214dbc935bc0763474ece3"}, - {file = "greenlet-1.1.3.post0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:64e10f303ea354500c927da5b59c3802196a07468332d292aef9ddaca08d03dd"}, - {file = "greenlet-1.1.3.post0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:eb6ac495dccb1520667cfea50d89e26f9ffb49fa28496dea2b95720d8b45eb54"}, - {file = "greenlet-1.1.3.post0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:88720794390002b0c8fa29e9602b395093a9a766b229a847e8d88349e418b28a"}, - {file = "greenlet-1.1.3.post0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39464518a2abe9c505a727af7c0b4efff2cf242aa168be5f0daa47649f4d7ca8"}, - {file = "greenlet-1.1.3.post0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0914f02fcaa8f84f13b2df4a81645d9e82de21ed95633765dd5cc4d3af9d7403"}, - {file = "greenlet-1.1.3.post0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96656c5f7c95fc02c36d4f6ef32f4e94bb0b6b36e6a002c21c39785a4eec5f5d"}, - {file = "greenlet-1.1.3.post0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:4f74aa0092602da2069df0bc6553919a15169d77bcdab52a21f8c5242898f519"}, - {file = "greenlet-1.1.3.post0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:3aeac044c324c1a4027dca0cde550bd83a0c0fbff7ef2c98df9e718a5086c194"}, - {file = "greenlet-1.1.3.post0-cp36-cp36m-win32.whl", hash = "sha256:fe7c51f8a2ab616cb34bc33d810c887e89117771028e1e3d3b77ca25ddeace04"}, - {file = "greenlet-1.1.3.post0-cp36-cp36m-win_amd64.whl", hash = "sha256:70048d7b2c07c5eadf8393e6398595591df5f59a2f26abc2f81abca09610492f"}, - {file = "greenlet-1.1.3.post0-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:66aa4e9a726b70bcbfcc446b7ba89c8cec40f405e51422c39f42dfa206a96a05"}, - {file = "greenlet-1.1.3.post0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:025b8de2273d2809f027d347aa2541651d2e15d593bbce0d5f502ca438c54136"}, - {file = "greenlet-1.1.3.post0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:82a38d7d2077128a017094aff334e67e26194f46bd709f9dcdacbf3835d47ef5"}, - {file = "greenlet-1.1.3.post0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7d20c3267385236b4ce54575cc8e9f43e7673fc761b069c820097092e318e3b"}, - {file = "greenlet-1.1.3.post0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c8ece5d1a99a2adcb38f69af2f07d96fb615415d32820108cd340361f590d128"}, - {file = "greenlet-1.1.3.post0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2794eef1b04b5ba8948c72cc606aab62ac4b0c538b14806d9c0d88afd0576d6b"}, - {file = "greenlet-1.1.3.post0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a8d24eb5cb67996fb84633fdc96dbc04f2d8b12bfcb20ab3222d6be271616b67"}, - {file = "greenlet-1.1.3.post0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0120a879aa2b1ac5118bce959ea2492ba18783f65ea15821680a256dfad04754"}, - {file = "greenlet-1.1.3.post0-cp37-cp37m-win32.whl", hash = "sha256:bef49c07fcb411c942da6ee7d7ea37430f830c482bf6e4b72d92fd506dd3a427"}, - {file = "greenlet-1.1.3.post0-cp37-cp37m-win_amd64.whl", hash = "sha256:62723e7eb85fa52e536e516ee2ac91433c7bb60d51099293671815ff49ed1c21"}, - {file = "greenlet-1.1.3.post0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:d25cdedd72aa2271b984af54294e9527306966ec18963fd032cc851a725ddc1b"}, - {file = "greenlet-1.1.3.post0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:924df1e7e5db27d19b1359dc7d052a917529c95ba5b8b62f4af611176da7c8ad"}, - {file = "greenlet-1.1.3.post0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ec615d2912b9ad807afd3be80bf32711c0ff9c2b00aa004a45fd5d5dde7853d9"}, - {file = "greenlet-1.1.3.post0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0971d37ae0eaf42344e8610d340aa0ad3d06cd2eee381891a10fe771879791f9"}, - {file = "greenlet-1.1.3.post0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:325f272eb997916b4a3fc1fea7313a8adb760934c2140ce13a2117e1b0a8095d"}, - {file = "greenlet-1.1.3.post0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d75afcbb214d429dacdf75e03a1d6d6c5bd1fa9c35e360df8ea5b6270fb2211c"}, - {file = "greenlet-1.1.3.post0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5c2d21c2b768d8c86ad935e404cc78c30d53dea009609c3ef3a9d49970c864b5"}, - {file = "greenlet-1.1.3.post0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:467b73ce5dcd89e381292fb4314aede9b12906c18fab903f995b86034d96d5c8"}, - {file = "greenlet-1.1.3.post0-cp38-cp38-win32.whl", hash = "sha256:8149a6865b14c33be7ae760bcdb73548bb01e8e47ae15e013bf7ef9290ca309a"}, - {file = "greenlet-1.1.3.post0-cp38-cp38-win_amd64.whl", hash = "sha256:104f29dd822be678ef6b16bf0035dcd43206a8a48668a6cae4d2fe9c7a7abdeb"}, - {file = "greenlet-1.1.3.post0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:c8c9301e3274276d3d20ab6335aa7c5d9e5da2009cccb01127bddb5c951f8870"}, - {file = "greenlet-1.1.3.post0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:8415239c68b2ec9de10a5adf1130ee9cb0ebd3e19573c55ba160ff0ca809e012"}, - {file = "greenlet-1.1.3.post0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:3c22998bfef3fcc1b15694818fc9b1b87c6cc8398198b96b6d355a7bcb8c934e"}, - {file = "greenlet-1.1.3.post0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0aa1845944e62f358d63fcc911ad3b415f585612946b8edc824825929b40e59e"}, - {file = "greenlet-1.1.3.post0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:890f633dc8cb307761ec566bc0b4e350a93ddd77dc172839be122be12bae3e10"}, - {file = "greenlet-1.1.3.post0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cf37343e43404699d58808e51f347f57efd3010cc7cee134cdb9141bd1ad9ea"}, - {file = "greenlet-1.1.3.post0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5edf75e7fcfa9725064ae0d8407c849456553a181ebefedb7606bac19aa1478b"}, - {file = "greenlet-1.1.3.post0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a954002064ee919b444b19c1185e8cce307a1f20600f47d6f4b6d336972c809"}, - {file = "greenlet-1.1.3.post0-cp39-cp39-win32.whl", hash = "sha256:2ccdc818cc106cc238ff7eba0d71b9c77be868fdca31d6c3b1347a54c9b187b2"}, - {file = "greenlet-1.1.3.post0-cp39-cp39-win_amd64.whl", hash = "sha256:91a84faf718e6f8b888ca63d0b2d6d185c8e2a198d2a7322d75c303e7097c8b7"}, - {file = "greenlet-1.1.3.post0.tar.gz", hash = "sha256:f5e09dc5c6e1796969fd4b775ea1417d70e49a5df29aaa8e5d10675d9e11872c"}, -] -h11 = [ - {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, - {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, -] -identify = [ - {file = "identify-2.5.6-py2.py3-none-any.whl", hash = "sha256:b276db7ec52d7e89f5bc4653380e33054ddc803d25875952ad90b0f012cbcdaa"}, - {file = "identify-2.5.6.tar.gz", hash = "sha256:6c32dbd747aa4ceee1df33f25fed0b0f6e0d65721b15bd151307ff7056d50245"}, -] -idna = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, -] -imagesize = [ - {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, - {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, -] -importlab = [ - {file = "importlab-0.8-py2.py3-none-any.whl", hash = "sha256:a009ccde7b549b16f3e6b034fea748febc8d45ded9e8a09370a8f994acfda25b"}, - {file = "importlab-0.8.tar.gz", hash = "sha256:b24b3aac3b073966ae42fb2d3a7764f3377b30bb72c0d411fe29134cc9276e86"}, -] -importlib-metadata = [ - {file = "importlib_metadata-5.0.0-py3-none-any.whl", hash = "sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43"}, - {file = "importlib_metadata-5.0.0.tar.gz", hash = "sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab"}, -] +clingo = [] +colorama = [] +contourpy = [] +coverage = [] +cycler = [] +debugpy = [] +decorator = [] +defusedxml = [] +distlib = [] +docutils = [] +entrypoints = [] +exceptiongroup = [] +executing = [] +fastapi = [] +fastjsonschema = [] +filelock = [] +flake8 = [] +flake8-black = [] +fonttools = [] +gitdb = [] +gitpython = [] +greenlet = [] +h11 = [] +identify = [] +idna = [] +imagesize = [] +importlab = [] +importlib-metadata = [] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] -ipykernel = [ - {file = "ipykernel-6.16.1-py3-none-any.whl", hash = "sha256:32eb7bdc5af57185e9a42b0dcef66413ef91a0490b378eae46cbdf0d4e0b5912"}, - {file = "ipykernel-6.16.1.tar.gz", hash = "sha256:3a27a550c1d682e7825f0f7732b0142b79ef1b21cd2e713cacac0c9847535f13"}, -] -ipython = [ - {file = "ipython-8.5.0-py3-none-any.whl", hash = "sha256:6f090e29ab8ef8643e521763a4f1f39dc3914db643122b1e9d3328ff2e43ada2"}, - {file = "ipython-8.5.0.tar.gz", hash = "sha256:097bdf5cd87576fd066179c9f7f208004f7a6864ee1b20f37d346c0bcb099f84"}, -] -ipython-genutils = [ - {file = "ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"}, - {file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"}, -] -ipywidgets = [ - {file = "ipywidgets-7.7.2-py2.py3-none-any.whl", hash = "sha256:3d47a7826cc6e2644d7cb90db26699451f8b42379cf63b761431b63d19984ca2"}, - {file = "ipywidgets-7.7.2.tar.gz", hash = "sha256:449ab8e7872d0f388ee5c5b3666b9d6af5e5618a5749fd62652680be37dff2af"}, -] +ipykernel = [] +ipython = [] +ipython-genutils = [] +ipywidgets = [] isort = [ {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, ] -jedi = [ - {file = "jedi-0.18.1-py2.py3-none-any.whl", hash = "sha256:637c9635fcf47945ceb91cd7f320234a7be540ded6f3e99a50cb6febdfd1ba8d"}, - {file = "jedi-0.18.1.tar.gz", hash = "sha256:74137626a64a99c8eb6ae5832d99b3bdd7d29a3850fe2aa80a4126b2a7d949ab"}, -] -jinja2 = [ - {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, - {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, -] -joblib = [ - {file = "joblib-1.2.0-py3-none-any.whl", hash = "sha256:091138ed78f800342968c523bdde947e7a305b8594b910a0fea2ab83c3c6d385"}, - {file = "joblib-1.2.0.tar.gz", hash = "sha256:e1cee4a79e4af22881164f218d4311f60074197fb707e082e803b61f6d137018"}, -] -json5 = [ - {file = "json5-0.9.10-py2.py3-none-any.whl", hash = "sha256:993189671e7412e9cdd8be8dc61cf402e8e579b35f1d1bb20ae6b09baa78bbce"}, - {file = "json5-0.9.10.tar.gz", hash = "sha256:ad9f048c5b5a4c3802524474ce40a622fae789860a86f10cc4f7e5f9cf9b46ab"}, -] -jsonschema = [ - {file = "jsonschema-3.2.0-py2.py3-none-any.whl", hash = "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163"}, - {file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"}, -] -jupyter-book = [ - {file = "jupyter-book-0.13.1.tar.gz", hash = "sha256:460a42fc7e09de46dd66c2aec18bbb10e282a9c80cdafe2e52c9ba3d51649d01"}, - {file = "jupyter_book-0.13.1-py3-none-any.whl", hash = "sha256:b46e8f320b6b136eef44b5ca72bee4d35d7dadc1293e6611b61914fd7e088fd0"}, -] -jupyter-cache = [ - {file = "jupyter-cache-0.4.3.tar.gz", hash = "sha256:4c9b5431b1d320bc68440c21fa0a155bbeb29c5b979bef72222e244a7bcd54fc"}, - {file = "jupyter_cache-0.4.3-py3-none-any.whl", hash = "sha256:6d5d662d81f565d18009e8dcfd3a56fb876af47eafead2a19ef0045aba8ffe3b"}, -] -jupyter-client = [ - {file = "jupyter_client-7.4.3-py3-none-any.whl", hash = "sha256:8845e3f5a339734b1ecc21d2100638aa1c7a145e356a31845f155cda5b624b1c"}, - {file = "jupyter_client-7.4.3.tar.gz", hash = "sha256:4fa2514cdb54dd9fbdcf7d7e4c5c3c8a973028168a8b4fc097b6aef625be13b0"}, -] -jupyter-core = [ - {file = "jupyter_core-4.11.2-py3-none-any.whl", hash = "sha256:3815e80ec5272c0c19aad087a0d2775df2852cfca8f5a17069e99c9350cecff8"}, - {file = "jupyter_core-4.11.2.tar.gz", hash = "sha256:c2909b9bc7dca75560a6c5ae78c34fd305ede31cd864da3c0d0bb2ed89aa9337"}, -] -jupyter-server = [ - {file = "jupyter_server-1.21.0-py3-none-any.whl", hash = "sha256:992531008544d77e05a16251cdfbd0bdff1b1efa14760c79b9cc776ac9214cf1"}, - {file = "jupyter_server-1.21.0.tar.gz", hash = "sha256:d0adca19913a3763359be7f0b8c2ea8bfde356f4b8edd8e3149d7d0fbfaa248b"}, -] -jupyter-server-mathjax = [ - {file = "jupyter_server_mathjax-0.2.6-py3-none-any.whl", hash = "sha256:416389dde2010df46d5fbbb7adb087a5607111070af65a1445391040f2babb5e"}, - {file = "jupyter_server_mathjax-0.2.6.tar.gz", hash = "sha256:bb1e6b6dc0686c1fe386a22b5886163db548893a99c2810c36399e9c4ca23943"}, -] -jupyter-sphinx = [ - {file = "jupyter_sphinx-0.3.2-py3-none-any.whl", hash = "sha256:301e36d0fb3007bb5802f6b65b60c24990eb99c983332a2ab6eecff385207dc9"}, - {file = "jupyter_sphinx-0.3.2.tar.gz", hash = "sha256:37fc9408385c45326ac79ca0452fbd7ae2bf0e97842d626d2844d4830e30aaf2"}, -] -jupyterlab = [ - {file = "jupyterlab-3.5.0-py3-none-any.whl", hash = "sha256:f433059fe0e12d75ea90a81a0b6721113bb132857e3ec2197780b6fe84cbcbde"}, - {file = "jupyterlab-3.5.0.tar.gz", hash = "sha256:e02556c8ea1b386963c4b464e4618aee153c5416b07ab481425c817a033323a2"}, -] -jupyterlab-pygments = [ - {file = "jupyterlab_pygments-0.2.2-py2.py3-none-any.whl", hash = "sha256:2405800db07c9f770863bcf8049a529c3dd4d3e28536638bd7c1c01d2748309f"}, - {file = "jupyterlab_pygments-0.2.2.tar.gz", hash = "sha256:7405d7fde60819d905a9fa8ce89e4cd830e318cdad22a0030f7a901da705585d"}, -] -jupyterlab-server = [ - {file = "jupyterlab_server-2.16.1-py3-none-any.whl", hash = "sha256:b572cd3e59b0722120f41d47f2363a0072765227184aea418b7cc276db4d75fd"}, - {file = "jupyterlab_server-2.16.1.tar.gz", hash = "sha256:fe0de558ff3bb447a32e24099aa7e17444fdbc8c08f6dbc0171cb1a0ae382d3f"}, -] -jupyterlab-widgets = [ - {file = "jupyterlab_widgets-1.1.1-py3-none-any.whl", hash = "sha256:90ab47d99da03a3697074acb23b2975ead1d6171aa41cb2812041a7f2a08177a"}, - {file = "jupyterlab_widgets-1.1.1.tar.gz", hash = "sha256:67d0ef1e407e0c42c8ab60b9d901cd7a4c68923650763f75bf17fb06c1943b79"}, -] -kiwisolver = [ - {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2f5e60fabb7343a836360c4f0919b8cd0d6dbf08ad2ca6b9cf90bf0c76a3c4f6"}, - {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:10ee06759482c78bdb864f4109886dff7b8a56529bc1609d4f1112b93fe6423c"}, - {file = "kiwisolver-1.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c79ebe8f3676a4c6630fd3f777f3cfecf9289666c84e775a67d1d358578dc2e3"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abbe9fa13da955feb8202e215c4018f4bb57469b1b78c7a4c5c7b93001699938"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7577c1987baa3adc4b3c62c33bd1118c3ef5c8ddef36f0f2c950ae0b199e100d"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8ad8285b01b0d4695102546b342b493b3ccc6781fc28c8c6a1bb63e95d22f09"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ed58b8acf29798b036d347791141767ccf65eee7f26bde03a71c944449e53de"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a68b62a02953b9841730db7797422f983935aeefceb1679f0fc85cbfbd311c32"}, - {file = "kiwisolver-1.4.4-cp310-cp310-win32.whl", hash = "sha256:e92a513161077b53447160b9bd8f522edfbed4bd9759e4c18ab05d7ef7e49408"}, - {file = "kiwisolver-1.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:3fe20f63c9ecee44560d0e7f116b3a747a5d7203376abeea292ab3152334d004"}, - {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ea21f66820452a3f5d1655f8704a60d66ba1191359b96541eaf457710a5fc6"}, - {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bc9db8a3efb3e403e4ecc6cd9489ea2bac94244f80c78e27c31dcc00d2790ac2"}, - {file = "kiwisolver-1.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d5b61785a9ce44e5a4b880272baa7cf6c8f48a5180c3e81c59553ba0cb0821ca"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c2dbb44c3f7e6c4d3487b31037b1bdbf424d97687c1747ce4ff2895795c9bf69"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6295ecd49304dcf3bfbfa45d9a081c96509e95f4b9d0eb7ee4ec0530c4a96514"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bd472dbe5e136f96a4b18f295d159d7f26fd399136f5b17b08c4e5f498cd494"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf7d9fce9bcc4752ca4a1b80aabd38f6d19009ea5cbda0e0856983cf6d0023f5"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d6601aed50c74e0ef02f4204da1816147a6d3fbdc8b3872d263338a9052c51"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:877272cf6b4b7e94c9614f9b10140e198d2186363728ed0f701c6eee1baec1da"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:db608a6757adabb32f1cfe6066e39b3706d8c3aa69bbc353a5b61edad36a5cb4"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5853eb494c71e267912275e5586fe281444eb5e722de4e131cddf9d442615626"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f0a1dbdb5ecbef0d34eb77e56fcb3e95bbd7e50835d9782a45df81cc46949750"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:283dffbf061a4ec60391d51e6155e372a1f7a4f5b15d59c8505339454f8989e4"}, - {file = "kiwisolver-1.4.4-cp311-cp311-win32.whl", hash = "sha256:d06adcfa62a4431d404c31216f0f8ac97397d799cd53800e9d3efc2fbb3cf14e"}, - {file = "kiwisolver-1.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e7da3fec7408813a7cebc9e4ec55afed2d0fd65c4754bc376bf03498d4e92686"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:62ac9cc684da4cf1778d07a89bf5f81b35834cb96ca523d3a7fb32509380cbf6"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41dae968a94b1ef1897cb322b39360a0812661dba7c682aa45098eb8e193dbdf"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02f79693ec433cb4b5f51694e8477ae83b3205768a6fb48ffba60549080e295b"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0611a0a2a518464c05ddd5a3a1a0e856ccc10e67079bb17f265ad19ab3c7597"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:db5283d90da4174865d520e7366801a93777201e91e79bacbac6e6927cbceede"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1041feb4cda8708ce73bb4dcb9ce1ccf49d553bf87c3954bdfa46f0c3f77252c"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-win32.whl", hash = "sha256:a553dadda40fef6bfa1456dc4be49b113aa92c2a9a9e8711e955618cd69622e3"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:03baab2d6b4a54ddbb43bba1a3a2d1627e82d205c5cf8f4c924dc49284b87166"}, - {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:841293b17ad704d70c578f1f0013c890e219952169ce8a24ebc063eecf775454"}, - {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f4f270de01dd3e129a72efad823da90cc4d6aafb64c410c9033aba70db9f1ff0"}, - {file = "kiwisolver-1.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f9f39e2f049db33a908319cf46624a569b36983c7c78318e9726a4cb8923b26c"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97528e64cb9ebeff9701e7938653a9951922f2a38bd847787d4a8e498cc83ae"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d1573129aa0fd901076e2bfb4275a35f5b7aa60fbfb984499d661ec950320b0"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad881edc7ccb9d65b0224f4e4d05a1e85cf62d73aab798943df6d48ab0cd79a1"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b428ef021242344340460fa4c9185d0b1f66fbdbfecc6c63eff4b7c29fad429d"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2e407cb4bd5a13984a6c2c0fe1845e4e41e96f183e5e5cd4d77a857d9693494c"}, - {file = "kiwisolver-1.4.4-cp38-cp38-win32.whl", hash = "sha256:75facbe9606748f43428fc91a43edb46c7ff68889b91fa31f53b58894503a191"}, - {file = "kiwisolver-1.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:5bce61af018b0cb2055e0e72e7d65290d822d3feee430b7b8203d8a855e78766"}, - {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8c808594c88a025d4e322d5bb549282c93c8e1ba71b790f539567932722d7bd8"}, - {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0a71d85ecdd570ded8ac3d1c0f480842f49a40beb423bb8014539a9f32a5897"}, - {file = "kiwisolver-1.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b533558eae785e33e8c148a8d9921692a9fe5aa516efbdff8606e7d87b9d5824"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:efda5fc8cc1c61e4f639b8067d118e742b812c930f708e6667a5ce0d13499e29"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7c43e1e1206cd421cd92e6b3280d4385d41d7166b3ed577ac20444b6995a445f"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc8d3bd6c72b2dd9decf16ce70e20abcb3274ba01b4e1c96031e0c4067d1e7cd"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ea39b0ccc4f5d803e3337dd46bcce60b702be4d86fd0b3d7531ef10fd99a1ac"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:968f44fdbf6dd757d12920d63b566eeb4d5b395fd2d00d29d7ef00a00582aac9"}, - {file = "kiwisolver-1.4.4-cp39-cp39-win32.whl", hash = "sha256:da7e547706e69e45d95e116e6939488d62174e033b763ab1496b4c29b76fabea"}, - {file = "kiwisolver-1.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:ba59c92039ec0a66103b1d5fe588fa546373587a7d68f5c96f743c3396afc04b"}, - {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:91672bacaa030f92fc2f43b620d7b337fd9a5af28b0d6ed3f77afc43c4a64b5a"}, - {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:787518a6789009c159453da4d6b683f468ef7a65bbde796bcea803ccf191058d"}, - {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da152d8cdcab0e56e4f45eb08b9aea6455845ec83172092f09b0e077ece2cf7a"}, - {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ecb1fa0db7bf4cff9dac752abb19505a233c7f16684c5826d1f11ebd9472b871"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:28bc5b299f48150b5f822ce68624e445040595a4ac3d59251703779836eceff9"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:81e38381b782cc7e1e46c4e14cd997ee6040768101aefc8fa3c24a4cc58e98f8"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2a66fdfb34e05b705620dd567f5a03f239a088d5a3f321e7b6ac3239d22aa286"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:872b8ca05c40d309ed13eb2e582cab0c5a05e81e987ab9c521bf05ad1d5cf5cb"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:70e7c2e7b750585569564e2e5ca9845acfaa5da56ac46df68414f29fea97be9f"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9f85003f5dfa867e86d53fac6f7e6f30c045673fa27b603c397753bebadc3008"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e307eb9bd99801f82789b44bb45e9f541961831c7311521b13a6c85afc09767"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1792d939ec70abe76f5054d3f36ed5656021dcad1322d1cc996d4e54165cef9"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6cb459eea32a4e2cf18ba5fcece2dbdf496384413bc1bae15583f19e567f3b2"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36dafec3d6d6088d34e2de6b85f9d8e2324eb734162fba59d2ba9ed7a2043d5b"}, - {file = "kiwisolver-1.4.4.tar.gz", hash = "sha256:d41997519fcba4a1e46eb4a2fe31bc12f0ff957b2b81bac28db24744f333e955"}, -] -latexcodec = [ - {file = "latexcodec-2.0.1-py2.py3-none-any.whl", hash = "sha256:c277a193638dc7683c4c30f6684e3db728a06efb0dc9cf346db8bd0aa6c5d271"}, - {file = "latexcodec-2.0.1.tar.gz", hash = "sha256:2aa2551c373261cefe2ad3a8953a6d6533e68238d180eb4bb91d7964adb3fe9a"}, -] -libcst = [ - {file = "libcst-0.4.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dc6f8965b6ca68d47e11321772887d81fa6fd8ea86e6ef87434ca2147de10747"}, - {file = "libcst-0.4.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a8f47d809df59fcd83058b777b86a300154ee3a1f1b0523a398a67b5f8affd4c"}, - {file = "libcst-0.4.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0d19de56aa733b4ef024527e3ce4896d4b0e9806889797f409ec24caa651a44"}, - {file = "libcst-0.4.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31da97bc986dc3f7a97f7d431fa911932aaf716d2f8bcda947fc964afd3b57cd"}, - {file = "libcst-0.4.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:71b2e2c5e33e53669c20de0853cecfac1ffb8657ee727ab8527140f39049b820"}, - {file = "libcst-0.4.7-cp310-cp310-win_amd64.whl", hash = "sha256:76fae68bd6b7ce069e267b3322c806b4305341cea78d161ae40e0ed641c8c660"}, - {file = "libcst-0.4.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bac76d69980bb3254f503f52128c256ef4d1bcbaabe4a17c3a9ebcd1fc0472c0"}, - {file = "libcst-0.4.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26f86535271eaefe84a99736875566a038449f92e1a2a61ea0b588d8359fbefd"}, - {file = "libcst-0.4.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:617f7fa2610a8c86cf22d8d03416f25391383d05bd0ad1ca8ef68023ddd6b4f6"}, - {file = "libcst-0.4.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c3637fffe476c5b4ee2225c6474b83382518f2c1b2fe4771039e06bdd7835a4a"}, - {file = "libcst-0.4.7-cp37-cp37m-win_amd64.whl", hash = "sha256:f56565124c2541adee0634e411b2126b3f335306d19e91ed2bfe52efa698b219"}, - {file = "libcst-0.4.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0ca2771ff3cfdf1f148349f89fcae64afa365213ed5c2703a69a89319325d0c8"}, - {file = "libcst-0.4.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aa438131b7befc7e5a3cbadb5a7b1506305de5d62262ea0556add0152f40925e"}, - {file = "libcst-0.4.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c6bd66a8be2ffad7b968d90dae86c62fd4739c0e011d71f3e76544a891ae743"}, - {file = "libcst-0.4.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:214a9c4f4f90cd5b4bfa18e17877da4dd9a896821d9af9be86fa3effdc289b9b"}, - {file = "libcst-0.4.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27a37f2b459a8b51a41e260bd89c24ae41ab1d658f610c91650c79b1bbf27138"}, - {file = "libcst-0.4.7-cp38-cp38-win_amd64.whl", hash = "sha256:2f6766391d90472f036b88a95251c87d498ab068c377724f212ab0cc20509a68"}, - {file = "libcst-0.4.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:234293aa8681a3d47fef1716c5622797a81cbe85a9381fe023815468cfe20eed"}, - {file = "libcst-0.4.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fa618dc359663a0a097c633452b104c1ca93365da7a811e655c6944f6b323239"}, - {file = "libcst-0.4.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3569d9901c18940632414fb7a0943bffd326db9f726a9c041664926820857815"}, - {file = "libcst-0.4.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:beb5347e46b419f782589da060e9300957e71d561aa5574309883b71f93c1dfe"}, - {file = "libcst-0.4.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e541ccfeebda1ae5f005fc120a5bf3e8ac9ccfda405ec3efd3df54fc4688ac3"}, - {file = "libcst-0.4.7-cp39-cp39-win_amd64.whl", hash = "sha256:3a2b7253cd2e3f0f8a3e23b5c2acb492811d865ef36e0816091c925f32b713d2"}, - {file = "libcst-0.4.7.tar.gz", hash = "sha256:95c52c2130531f6e726a3b077442cfd486975435fecf3db8224d43fba7b85099"}, -] -linkify-it-py = [ - {file = "linkify-it-py-1.0.3.tar.gz", hash = "sha256:2b3f168d5ce75e3a425e34b341a6b73e116b5d9ed8dbbbf5dc7456843b7ce2ee"}, - {file = "linkify_it_py-1.0.3-py3-none-any.whl", hash = "sha256:11e29f00150cddaa8f434153f103c14716e7e097a8fd372d9eb1ed06ed91524d"}, -] -lxml = [ - {file = "lxml-4.9.1-cp27-cp27m-macosx_10_15_x86_64.whl", hash = "sha256:98cafc618614d72b02185ac583c6f7796202062c41d2eeecdf07820bad3295ed"}, - {file = "lxml-4.9.1-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c62e8dd9754b7debda0c5ba59d34509c4688f853588d75b53c3791983faa96fc"}, - {file = "lxml-4.9.1-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:21fb3d24ab430fc538a96e9fbb9b150029914805d551deeac7d7822f64631dfc"}, - {file = "lxml-4.9.1-cp27-cp27m-win32.whl", hash = "sha256:86e92728ef3fc842c50a5cb1d5ba2bc66db7da08a7af53fb3da79e202d1b2cd3"}, - {file = "lxml-4.9.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4cfbe42c686f33944e12f45a27d25a492cc0e43e1dc1da5d6a87cbcaf2e95627"}, - {file = "lxml-4.9.1-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dad7b164905d3e534883281c050180afcf1e230c3d4a54e8038aa5cfcf312b84"}, - {file = "lxml-4.9.1-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a614e4afed58c14254e67862456d212c4dcceebab2eaa44d627c2ca04bf86837"}, - {file = "lxml-4.9.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f9ced82717c7ec65a67667bb05865ffe38af0e835cdd78728f1209c8fffe0cad"}, - {file = "lxml-4.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:d9fc0bf3ff86c17348dfc5d322f627d78273eba545db865c3cd14b3f19e57fa5"}, - {file = "lxml-4.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e5f66bdf0976ec667fc4594d2812a00b07ed14d1b44259d19a41ae3fff99f2b8"}, - {file = "lxml-4.9.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fe17d10b97fdf58155f858606bddb4e037b805a60ae023c009f760d8361a4eb8"}, - {file = "lxml-4.9.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8caf4d16b31961e964c62194ea3e26a0e9561cdf72eecb1781458b67ec83423d"}, - {file = "lxml-4.9.1-cp310-cp310-win32.whl", hash = "sha256:4780677767dd52b99f0af1f123bc2c22873d30b474aa0e2fc3fe5e02217687c7"}, - {file = "lxml-4.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:b122a188cd292c4d2fcd78d04f863b789ef43aa129b233d7c9004de08693728b"}, - {file = "lxml-4.9.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:be9eb06489bc975c38706902cbc6888f39e946b81383abc2838d186f0e8b6a9d"}, - {file = "lxml-4.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f1be258c4d3dc609e654a1dc59d37b17d7fef05df912c01fc2e15eb43a9735f3"}, - {file = "lxml-4.9.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:927a9dd016d6033bc12e0bf5dee1dde140235fc8d0d51099353c76081c03dc29"}, - {file = "lxml-4.9.1-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9232b09f5efee6a495a99ae6824881940d6447debe272ea400c02e3b68aad85d"}, - {file = "lxml-4.9.1-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:04da965dfebb5dac2619cb90fcf93efdb35b3c6994fea58a157a834f2f94b318"}, - {file = "lxml-4.9.1-cp35-cp35m-win32.whl", hash = "sha256:4d5bae0a37af799207140652a700f21a85946f107a199bcb06720b13a4f1f0b7"}, - {file = "lxml-4.9.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4878e667ebabe9b65e785ac8da4d48886fe81193a84bbe49f12acff8f7a383a4"}, - {file = "lxml-4.9.1-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:1355755b62c28950f9ce123c7a41460ed9743c699905cbe664a5bcc5c9c7c7fb"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:bcaa1c495ce623966d9fc8a187da80082334236a2a1c7e141763ffaf7a405067"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6eafc048ea3f1b3c136c71a86db393be36b5b3d9c87b1c25204e7d397cee9536"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:13c90064b224e10c14dcdf8086688d3f0e612db53766e7478d7754703295c7c8"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:206a51077773c6c5d2ce1991327cda719063a47adc02bd703c56a662cdb6c58b"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e8f0c9d65da595cfe91713bc1222af9ecabd37971762cb830dea2fc3b3bb2acf"}, - {file = "lxml-4.9.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8f0a4d179c9a941eb80c3a63cdb495e539e064f8054230844dcf2fcb812b71d3"}, - {file = "lxml-4.9.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:830c88747dce8a3e7525defa68afd742b4580df6aa2fdd6f0855481e3994d391"}, - {file = "lxml-4.9.1-cp36-cp36m-win32.whl", hash = "sha256:1e1cf47774373777936c5aabad489fef7b1c087dcd1f426b621fda9dcc12994e"}, - {file = "lxml-4.9.1-cp36-cp36m-win_amd64.whl", hash = "sha256:5974895115737a74a00b321e339b9c3f45c20275d226398ae79ac008d908bff7"}, - {file = "lxml-4.9.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:1423631e3d51008871299525b541413c9b6c6423593e89f9c4cfbe8460afc0a2"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:2aaf6a0a6465d39b5ca69688fce82d20088c1838534982996ec46633dc7ad6cc"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:9f36de4cd0c262dd9927886cc2305aa3f2210db437aa4fed3fb4940b8bf4592c"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ae06c1e4bc60ee076292e582a7512f304abdf6c70db59b56745cca1684f875a4"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:57e4d637258703d14171b54203fd6822fda218c6c2658a7d30816b10995f29f3"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6d279033bf614953c3fc4a0aa9ac33a21e8044ca72d4fa8b9273fe75359d5cca"}, - {file = "lxml-4.9.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a60f90bba4c37962cbf210f0188ecca87daafdf60271f4c6948606e4dabf8785"}, - {file = "lxml-4.9.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6ca2264f341dd81e41f3fffecec6e446aa2121e0b8d026fb5130e02de1402785"}, - {file = "lxml-4.9.1-cp37-cp37m-win32.whl", hash = "sha256:27e590352c76156f50f538dbcebd1925317a0f70540f7dc8c97d2931c595783a"}, - {file = "lxml-4.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:eea5d6443b093e1545ad0210e6cf27f920482bfcf5c77cdc8596aec73523bb7e"}, - {file = "lxml-4.9.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:f05251bbc2145349b8d0b77c0d4e5f3b228418807b1ee27cefb11f69ed3d233b"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:487c8e61d7acc50b8be82bda8c8d21d20e133c3cbf41bd8ad7eb1aaeb3f07c97"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8d1a92d8e90b286d491e5626af53afef2ba04da33e82e30744795c71880eaa21"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:b570da8cd0012f4af9fa76a5635cd31f707473e65a5a335b186069d5c7121ff2"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ef87fca280fb15342726bd5f980f6faf8b84a5287fcc2d4962ea8af88b35130"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:93e414e3206779ef41e5ff2448067213febf260ba747fc65389a3ddaa3fb8715"}, - {file = "lxml-4.9.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6653071f4f9bac46fbc30f3c7838b0e9063ee335908c5d61fb7a4a86c8fd2036"}, - {file = "lxml-4.9.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:32a73c53783becdb7eaf75a2a1525ea8e49379fb7248c3eeefb9412123536387"}, - {file = "lxml-4.9.1-cp38-cp38-win32.whl", hash = "sha256:1a7c59c6ffd6ef5db362b798f350e24ab2cfa5700d53ac6681918f314a4d3b94"}, - {file = "lxml-4.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:1436cf0063bba7888e43f1ba8d58824f085410ea2025befe81150aceb123e345"}, - {file = "lxml-4.9.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:4beea0f31491bc086991b97517b9683e5cfb369205dac0148ef685ac12a20a67"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:41fb58868b816c202e8881fd0f179a4644ce6e7cbbb248ef0283a34b73ec73bb"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:bd34f6d1810d9354dc7e35158aa6cc33456be7706df4420819af6ed966e85448"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:edffbe3c510d8f4bf8640e02ca019e48a9b72357318383ca60e3330c23aaffc7"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6d949f53ad4fc7cf02c44d6678e7ff05ec5f5552b235b9e136bd52e9bf730b91"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:079b68f197c796e42aa80b1f739f058dcee796dc725cc9a1be0cdb08fc45b000"}, - {file = "lxml-4.9.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9c3a88d20e4fe4a2a4a84bf439a5ac9c9aba400b85244c63a1ab7088f85d9d25"}, - {file = "lxml-4.9.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4e285b5f2bf321fc0857b491b5028c5f276ec0c873b985d58d7748ece1d770dd"}, - {file = "lxml-4.9.1-cp39-cp39-win32.whl", hash = "sha256:ef72013e20dd5ba86a8ae1aed7f56f31d3374189aa8b433e7b12ad182c0d2dfb"}, - {file = "lxml-4.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:10d2017f9150248563bb579cd0d07c61c58da85c922b780060dcc9a3aa9f432d"}, - {file = "lxml-4.9.1-pp37-pypy37_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0538747a9d7827ce3e16a8fdd201a99e661c7dee3c96c885d8ecba3c35d1032c"}, - {file = "lxml-4.9.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:0645e934e940107e2fdbe7c5b6fb8ec6232444260752598bc4d09511bd056c0b"}, - {file = "lxml-4.9.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6daa662aba22ef3258934105be2dd9afa5bb45748f4f702a3b39a5bf53a1f4dc"}, - {file = "lxml-4.9.1-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:603a464c2e67d8a546ddaa206d98e3246e5db05594b97db844c2f0a1af37cf5b"}, - {file = "lxml-4.9.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c4b2e0559b68455c085fb0f6178e9752c4be3bba104d6e881eb5573b399d1eb2"}, - {file = "lxml-4.9.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0f3f0059891d3254c7b5fb935330d6db38d6519ecd238ca4fce93c234b4a0f73"}, - {file = "lxml-4.9.1-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c852b1530083a620cb0de5f3cd6826f19862bafeaf77586f1aef326e49d95f0c"}, - {file = "lxml-4.9.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:287605bede6bd36e930577c5925fcea17cb30453d96a7b4c63c14a257118dbb9"}, - {file = "lxml-4.9.1.tar.gz", hash = "sha256:fe749b052bb7233fe5d072fcb549221a8cb1a16725c47c37e42b0b9cb3ff2c3f"}, -] -markdown-it-py = [ - {file = "markdown-it-py-1.1.0.tar.gz", hash = "sha256:36be6bb3ad987bfdb839f5ba78ddf094552ca38ccbd784ae4f74a4e1419fc6e3"}, - {file = "markdown_it_py-1.1.0-py3-none-any.whl", hash = "sha256:98080fc0bc34c4f2bcf0846a096a9429acbd9d5d8e67ed34026c03c61c464389"}, -] -markupsafe = [ - {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-win32.whl", hash = "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-win32.whl", hash = "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-win32.whl", hash = "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, - {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, -] -matplotlib = [ - {file = "matplotlib-3.6.1-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:7730e60e751cfcfe7fcb223cf03c0b979e9a064c239783ad37929d340a364cef"}, - {file = "matplotlib-3.6.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:9dd40505ccc526acaf9a5db1b3029e237c64b58f1249983b28a291c2d6a1d0fa"}, - {file = "matplotlib-3.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:85948b303534b69fd771126764cf883fde2af9b003eb5778cb60f3b46f93d3f6"}, - {file = "matplotlib-3.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71eced071825005011cdc64efbae2e2c76b8209c18aa487dedf69796fe4b1e40"}, - {file = "matplotlib-3.6.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:220314c2d6b9ca11570d7cd4b841c9f3137546f188336003b9fb8def4dcb804d"}, - {file = "matplotlib-3.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2cc5d726d4d42865f909c5208a7841109d76584950dd0587b01a77cc279d4ab7"}, - {file = "matplotlib-3.6.1-cp310-cp310-win32.whl", hash = "sha256:183bf3ac6a6023ee590aa4b677f391ceed65ec0d6b930901a8483c267bd12995"}, - {file = "matplotlib-3.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:a68b91ac7e6bb26100a540a033f54c95fe06d9c0aa51312c2a52d07d1bde78f4"}, - {file = "matplotlib-3.6.1-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:4648f0d79a87bf50ee740058305c91091ee5e1fbb71a7d2f5fe6707bfe328d1c"}, - {file = "matplotlib-3.6.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9403764017d20ff570f7ce973a8b9637f08a6109118f4e0ce6c7493d8849a0d3"}, - {file = "matplotlib-3.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4c8b5a243dd29d50289d694e931bd6cb6ae0b5bd654d12c647543d63862540c"}, - {file = "matplotlib-3.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1effccef0cea2d4da9feeed22079adf6786f92c800a7d0d2ef2104318a1c66c"}, - {file = "matplotlib-3.6.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8dc25473319afabe49150267e54648ac559c33b0fc2a80c8caecfbbc2948a820"}, - {file = "matplotlib-3.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47cb088bbce82ae9fc2edf3c25e56a5c6142ce2553fea2b781679f960a70c207"}, - {file = "matplotlib-3.6.1-cp311-cp311-win32.whl", hash = "sha256:4d3b0e0a4611bd22065bbf47e9b2f689ac9e575bcb850a9f0ae2bbed75cab956"}, - {file = "matplotlib-3.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:e3c116e779fbbf421a9e4d3060db259a9bb486d98f4e3c5a0877c599bd173582"}, - {file = "matplotlib-3.6.1-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:565f514dec81a41cbed10eb6011501879695087fc2787fb89423a466508abbbd"}, - {file = "matplotlib-3.6.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:05e86446562063d6186ff6d700118c0dbd5dccc403a6187351ee526c48878f10"}, - {file = "matplotlib-3.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8245e85fd793f58edf29b8a9e3be47e8ecf76ea1a1e8240545f2746181ca5787"}, - {file = "matplotlib-3.6.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1e2c75d5d1ff6b7ef9870360bfa23bea076b8dc0945a60d19453d7619ed9ea8f"}, - {file = "matplotlib-3.6.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c9756a8e69f6e1f76d47eb42132175b6814da1fbeae0545304c6d0fc2aae252a"}, - {file = "matplotlib-3.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f5788168da2661b42f7468063b725cc73fdbeeb80f2704cb2d8c415e9a57c50"}, - {file = "matplotlib-3.6.1-cp38-cp38-win32.whl", hash = "sha256:0bab7564aafd5902128d54b68dca04f5755413fb6b502100bb0235a545882c48"}, - {file = "matplotlib-3.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:3c53486278a0629fd892783271dc994b962fba8dfe207445d039e14f1928ea46"}, - {file = "matplotlib-3.6.1-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:27337bcb38d5db7430c14f350924542d75416ec1546d5d9d9f39b362b71db3fb"}, - {file = "matplotlib-3.6.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:fad858519bd6d52dbfeebdbe04d00dd8e932ed436f1c535e61bcc970a96c11e4"}, - {file = "matplotlib-3.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4a3d903588b519b38ed085d0ae762a1dcd4b70164617292175cfd91b90d6c415"}, - {file = "matplotlib-3.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87bdbd37d0a41e025879863fe9b17bab15c0421313bc33e77e5e1aa54215c9c5"}, - {file = "matplotlib-3.6.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e632f66218811d4cf8b7a2a649e25ec15406c3c498f72d19e2bcf8377f38445d"}, - {file = "matplotlib-3.6.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ddd58324dc9a77e2e56d7b7aea7dbd0575b6f7cd1333c3ca9d388ac70978344"}, - {file = "matplotlib-3.6.1-cp39-cp39-win32.whl", hash = "sha256:12ab21d0cad122f5b23688d453a0280676e7c42f634f0dbd093d15d42d142b1f"}, - {file = "matplotlib-3.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:563896ba269324872ace436a57775dcc8322678a9496b28a8c25cdafa5ec2b92"}, - {file = "matplotlib-3.6.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:52935b7d4ccbf0dbc9cf454dbb10ca99c11cbe8da9467596b96e5e21fd4dfc5c"}, - {file = "matplotlib-3.6.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87027ff7b2edeb14476900261ef04d4beae949e1dfa0a3eb3ad6a6efbf9d0e1d"}, - {file = "matplotlib-3.6.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4de03085afb3b80fab341afaf8e60dfe06ce439b6dfed55d657cf34a7bc3c40"}, - {file = "matplotlib-3.6.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b53387d4e59432ff221540a4ffb5ee9669c69417805e4faf0148a00d701c61f9"}, - {file = "matplotlib-3.6.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:02561141c434154f7bae8e5449909d152367cb40aa57bfb2a27f2748b9c5f95f"}, - {file = "matplotlib-3.6.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0161ebf87518ecfe0980c942d5f0d5df0e080c1746ebaab2027a969967014b7"}, - {file = "matplotlib-3.6.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2469f57e4c5cc0e85eddc7b30995ea9c404a78c0b1856da75d1a5887156ca350"}, - {file = "matplotlib-3.6.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5f97141e05baf160c3ec125f06ceb2a44c9bb62f42fcb8ee1c05313c73e99432"}, - {file = "matplotlib-3.6.1.tar.gz", hash = "sha256:e2d1b7225666f7e1bcc94c0bc9c587a82e3e8691da4757e357e5c2515222ee37"}, -] -matplotlib-inline = [ - {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"}, - {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"}, -] +jedi = [] +jinja2 = [] +joblib = [] +json5 = [] +jsonschema = [] +jupyter-book = [] +jupyter-cache = [] +jupyter-client = [] +jupyter-core = [] +jupyter-server = [] +jupyter-server-mathjax = [] +jupyter-sphinx = [] +jupyterlab = [] +jupyterlab-pygments = [] +jupyterlab-server = [] +jupyterlab-widgets = [] +kiwisolver = [] +latexcodec = [] +libcst = [] +linkify-it-py = [] +lxml = [] +markdown-it-py = [] +markupsafe = [] +matplotlib = [] +matplotlib-inline = [] mccabe = [ {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, ] -mdit-py-plugins = [ - {file = "mdit-py-plugins-0.2.8.tar.gz", hash = "sha256:5991cef645502e80a5388ec4fc20885d2313d4871e8b8e320ca2de14ac0c015f"}, - {file = "mdit_py_plugins-0.2.8-py3-none-any.whl", hash = "sha256:1833bf738e038e35d89cb3a07eb0d227ed647ce7dd357579b65343740c6d249c"}, -] -mistune = [ - {file = "mistune-0.8.4-py2.py3-none-any.whl", hash = "sha256:88a1051873018da288eee8538d476dffe1262495144b33ecb586c4ab266bb8d4"}, - {file = "mistune-0.8.4.tar.gz", hash = "sha256:59a3429db53c50b5c6bcc8a07f8848cb00d7dc8bdb431a4ab41920d201d4756e"}, -] -mypy = [ - {file = "mypy-0.982-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5085e6f442003fa915aeb0a46d4da58128da69325d8213b4b35cc7054090aed5"}, - {file = "mypy-0.982-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:41fd1cf9bc0e1c19b9af13a6580ccb66c381a5ee2cf63ee5ebab747a4badeba3"}, - {file = "mypy-0.982-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f793e3dd95e166b66d50e7b63e69e58e88643d80a3dcc3bcd81368e0478b089c"}, - {file = "mypy-0.982-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86ebe67adf4d021b28c3f547da6aa2cce660b57f0432617af2cca932d4d378a6"}, - {file = "mypy-0.982-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:175f292f649a3af7082fe36620369ffc4661a71005aa9f8297ea473df5772046"}, - {file = "mypy-0.982-cp310-cp310-win_amd64.whl", hash = "sha256:8ee8c2472e96beb1045e9081de8e92f295b89ac10c4109afdf3a23ad6e644f3e"}, - {file = "mypy-0.982-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58f27ebafe726a8e5ccb58d896451dd9a662a511a3188ff6a8a6a919142ecc20"}, - {file = "mypy-0.982-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6af646bd46f10d53834a8e8983e130e47d8ab2d4b7a97363e35b24e1d588947"}, - {file = "mypy-0.982-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7aeaa763c7ab86d5b66ff27f68493d672e44c8099af636d433a7f3fa5596d40"}, - {file = "mypy-0.982-cp37-cp37m-win_amd64.whl", hash = "sha256:724d36be56444f569c20a629d1d4ee0cb0ad666078d59bb84f8f887952511ca1"}, - {file = "mypy-0.982-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:14d53cdd4cf93765aa747a7399f0961a365bcddf7855d9cef6306fa41de01c24"}, - {file = "mypy-0.982-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:26ae64555d480ad4b32a267d10cab7aec92ff44de35a7cd95b2b7cb8e64ebe3e"}, - {file = "mypy-0.982-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6389af3e204975d6658de4fb8ac16f58c14e1bacc6142fee86d1b5b26aa52bda"}, - {file = "mypy-0.982-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b35ce03a289480d6544aac85fa3674f493f323d80ea7226410ed065cd46f206"}, - {file = "mypy-0.982-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c6e564f035d25c99fd2b863e13049744d96bd1947e3d3d2f16f5828864506763"}, - {file = "mypy-0.982-cp38-cp38-win_amd64.whl", hash = "sha256:cebca7fd333f90b61b3ef7f217ff75ce2e287482206ef4a8b18f32b49927b1a2"}, - {file = "mypy-0.982-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a705a93670c8b74769496280d2fe6cd59961506c64f329bb179970ff1d24f9f8"}, - {file = "mypy-0.982-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:75838c649290d83a2b83a88288c1eb60fe7a05b36d46cbea9d22efc790002146"}, - {file = "mypy-0.982-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:91781eff1f3f2607519c8b0e8518aad8498af1419e8442d5d0afb108059881fc"}, - {file = "mypy-0.982-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaa97b9ddd1dd9901a22a879491dbb951b5dec75c3b90032e2baa7336777363b"}, - {file = "mypy-0.982-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a692a8e7d07abe5f4b2dd32d731812a0175626a90a223d4b58f10f458747dd8a"}, - {file = "mypy-0.982-cp39-cp39-win_amd64.whl", hash = "sha256:eb7a068e503be3543c4bd329c994103874fa543c1727ba5288393c21d912d795"}, - {file = "mypy-0.982-py3-none-any.whl", hash = "sha256:1021c241e8b6e1ca5a47e4d52601274ac078a89845cfde66c6d5f769819ffa1d"}, - {file = "mypy-0.982.tar.gz", hash = "sha256:85f7a343542dc8b1ed0a888cdd34dca56462654ef23aa673907305b260b3d746"}, -] +mdit-py-plugins = [] +mistune = [] +mypy = [] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] -myst-nb = [ - {file = "myst-nb-0.13.2.tar.gz", hash = "sha256:81e0a4f186bb35c487f5443c7005a474d68ffb58f518f469102d1db7b452066a"}, - {file = "myst_nb-0.13.2-py3-none-any.whl", hash = "sha256:1b9ea3a04c9e0eee05145aa297d2feeabb94c4e23e3047b92efa011ddba4f4b4"}, -] -myst-parser = [ - {file = "myst-parser-0.15.2.tar.gz", hash = "sha256:f7f3b2d62db7655cde658eb5d62b2ec2a4631308137bd8d10f296a40d57bbbeb"}, - {file = "myst_parser-0.15.2-py3-none-any.whl", hash = "sha256:40124b6f27a4c42ac7f06b385e23a9dcd03d84801e9c7130b59b3729a554b1f9"}, -] -nbclassic = [ - {file = "nbclassic-0.4.7-py3-none-any.whl", hash = "sha256:d71d18aa6605eaf59e9b99b34c96360af45847f2a30ee2fefbe2f7bed4bc3df2"}, - {file = "nbclassic-0.4.7.tar.gz", hash = "sha256:1e0470583b55089c427940ed31b8a866ffef7ccab101494e409efe5ac7ba9897"}, -] -nbclient = [ - {file = "nbclient-0.5.13-py3-none-any.whl", hash = "sha256:47ac905af59379913c1f8f541098d2550153cf8dc58553cbe18c702b181518b0"}, - {file = "nbclient-0.5.13.tar.gz", hash = "sha256:40c52c9b5e3c31faecaee69f202b3f53e38d7c1c563de0fadde9d7eda0fdafe8"}, -] -nbconvert = [ - {file = "nbconvert-6.5.4-py3-none-any.whl", hash = "sha256:d679a947f849a966cbbd0bf6e7fedcfdb64be3b20ce7cef11ad55c13f5820e19"}, - {file = "nbconvert-6.5.4.tar.gz", hash = "sha256:9e3c7c6d491374cbdd5f35d268c05809357716d346f4573186bbeab32ee50bc1"}, -] -nbdime = [ - {file = "nbdime-3.1.1-py2.py3-none-any.whl", hash = "sha256:ea4ddf919e3035800ef8bd5552b814522207cb154ca7512565e4539a54c74dbf"}, - {file = "nbdime-3.1.1.tar.gz", hash = "sha256:67767320e971374f701a175aa59abd3a554723039d39fae908e72d16330d648b"}, -] -nbformat = [ - {file = "nbformat-5.7.0-py3-none-any.whl", hash = "sha256:1b05ec2c552c2f1adc745f4eddce1eac8ca9ffd59bb9fd859e827eaa031319f9"}, - {file = "nbformat-5.7.0.tar.gz", hash = "sha256:1d4760c15c1a04269ef5caf375be8b98dd2f696e5eb9e603ec2bf091f9b0d3f3"}, -] -nest-asyncio = [ - {file = "nest_asyncio-1.5.6-py3-none-any.whl", hash = "sha256:b9a953fb40dceaa587d109609098db21900182b16440652454a146cffb06e8b8"}, - {file = "nest_asyncio-1.5.6.tar.gz", hash = "sha256:d267cc1ff794403f7df692964d1d2a3fa9418ffea2a3f6859a439ff482fef290"}, -] -networkx = [ - {file = "networkx-2.8.3-py3-none-any.whl", hash = "sha256:f151edac6f9b0cf11fecce93e236ac22b499bb9ff8d6f8393b9fef5ad09506cc"}, - {file = "networkx-2.8.3.tar.gz", hash = "sha256:67fab04a955a73eb660fe7bf281b6fa71a003bc6e23a92d2f6227654c5223dbe"}, -] -ninja = [ - {file = "ninja-1.10.2.4-py2.py3-none-macosx_10_9_universal2.macosx_10_9_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:b0350784b37c5080223ec1bedc507153cc714b502c17dd5a64552e930b0dca25"}, - {file = "ninja-1.10.2.4-py2.py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b86a4e4ba2ed999d8b10f2b3f2ed56d7457ff647268f4098dd0b63dd145ede32"}, - {file = "ninja-1.10.2.4-py2.py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b12cfed6382e510a597b3d08d7eec96664f7c8b8ee436eef645736c453d1c135"}, - {file = "ninja-1.10.2.4-py2.py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:24e3bc4713667a9a1d15484ad2bb77bbaedb1e6d45254cb03f7964b8b497231a"}, - {file = "ninja-1.10.2.4-py2.py3-none-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3fa6e69838613815c80abcaca34681c5b7cf15bf921543e518f5c918d7098bb7"}, - {file = "ninja-1.10.2.4-py2.py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:327c319176c5a4af21908b727b776e9f5caf275680403da632821ba071fd6296"}, - {file = "ninja-1.10.2.4-py2.py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:251fb21cd6691accd0d95e28721ad8a50a6ec0ace97f9a8de3976f39301686f6"}, - {file = "ninja-1.10.2.4-py2.py3-none-musllinux_1_1_i686.whl", hash = "sha256:685daebd1bc21480256351000a01dfb520636832fa65efc9f121474ff640e3df"}, - {file = "ninja-1.10.2.4-py2.py3-none-musllinux_1_1_ppc64le.whl", hash = "sha256:34c8e44f6e2e35ff9444994bfc7bf451c8d4bf15e31ad1e3ef7b06f78647b35b"}, - {file = "ninja-1.10.2.4-py2.py3-none-musllinux_1_1_s390x.whl", hash = "sha256:b264085e409533aecb57040c5e90fbfb64db91a61575c7e637411780446412fa"}, - {file = "ninja-1.10.2.4-py2.py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:3300f3f37d62dcc7bdd19284dff9eaed7d629f4ed2725019a6ce3291c655fb83"}, - {file = "ninja-1.10.2.4-py2.py3-none-win32.whl", hash = "sha256:5b973b1ce7075e9091db290adbbf93ba9066a94f97c369d0ff631251c633e81b"}, - {file = "ninja-1.10.2.4-py2.py3-none-win_amd64.whl", hash = "sha256:ea245943a9849e5b1ebd74c1a4c1edd2c9801b62c0386165c7ac47623e353627"}, - {file = "ninja-1.10.2.4.tar.gz", hash = "sha256:da7a6d9b2ed2018165fbf90068e2c64da08f2568c700fdb8abea07a245dc4664"}, -] -nodeenv = [ - {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"}, - {file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"}, -] -notebook = [ - {file = "notebook-6.5.0-py3-none-any.whl", hash = "sha256:9a8617be63ef54d14c79c4089b714359dfee49a945ae723220fea282421e0f6e"}, - {file = "notebook-6.5.0.tar.gz", hash = "sha256:c5b747b047aa934da5f8f52d3b7219e7338684890d8dd6d9cac5d67d4513f924"}, -] -notebook-shim = [ - {file = "notebook_shim-0.2.0-py3-none-any.whl", hash = "sha256:481711abddfb2e5305b83cf0efe18475824eb47d1ba9f87f66a8c574b8b5c9e4"}, - {file = "notebook_shim-0.2.0.tar.gz", hash = "sha256:fdb81febb05932c6d19e44e10382ce05469cac5e1b6e99b49be6159ddb5e4804"}, -] -numpy = [ - {file = "numpy-1.23.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:95d79ada05005f6f4f337d3bb9de8a7774f259341c70bc88047a1f7b96a4bcb2"}, - {file = "numpy-1.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:926db372bc4ac1edf81cfb6c59e2a881606b409ddc0d0920b988174b2e2a767f"}, - {file = "numpy-1.23.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c237129f0e732885c9a6076a537e974160482eab8f10db6292e92154d4c67d71"}, - {file = "numpy-1.23.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8365b942f9c1a7d0f0dc974747d99dd0a0cdfc5949a33119caf05cb314682d3"}, - {file = "numpy-1.23.4-cp310-cp310-win32.whl", hash = "sha256:2341f4ab6dba0834b685cce16dad5f9b6606ea8a00e6da154f5dbded70fdc4dd"}, - {file = "numpy-1.23.4-cp310-cp310-win_amd64.whl", hash = "sha256:d331afac87c92373826af83d2b2b435f57b17a5c74e6268b79355b970626e329"}, - {file = "numpy-1.23.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:488a66cb667359534bc70028d653ba1cf307bae88eab5929cd707c761ff037db"}, - {file = "numpy-1.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ce03305dd694c4873b9429274fd41fc7eb4e0e4dea07e0af97a933b079a5814f"}, - {file = "numpy-1.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8981d9b5619569899666170c7c9748920f4a5005bf79c72c07d08c8a035757b0"}, - {file = "numpy-1.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a70a7d3ce4c0e9284e92285cba91a4a3f5214d87ee0e95928f3614a256a1488"}, - {file = "numpy-1.23.4-cp311-cp311-win32.whl", hash = "sha256:5e13030f8793e9ee42f9c7d5777465a560eb78fa7e11b1c053427f2ccab90c79"}, - {file = "numpy-1.23.4-cp311-cp311-win_amd64.whl", hash = "sha256:7607b598217745cc40f751da38ffd03512d33ec06f3523fb0b5f82e09f6f676d"}, - {file = "numpy-1.23.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7ab46e4e7ec63c8a5e6dbf5c1b9e1c92ba23a7ebecc86c336cb7bf3bd2fb10e5"}, - {file = "numpy-1.23.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a8aae2fb3180940011b4862b2dd3756616841c53db9734b27bb93813cd79fce6"}, - {file = "numpy-1.23.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c053d7557a8f022ec823196d242464b6955a7e7e5015b719e76003f63f82d0f"}, - {file = "numpy-1.23.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0882323e0ca4245eb0a3d0a74f88ce581cc33aedcfa396e415e5bba7bf05f68"}, - {file = "numpy-1.23.4-cp38-cp38-win32.whl", hash = "sha256:dada341ebb79619fe00a291185bba370c9803b1e1d7051610e01ed809ef3a4ba"}, - {file = "numpy-1.23.4-cp38-cp38-win_amd64.whl", hash = "sha256:0fe563fc8ed9dc4474cbf70742673fc4391d70f4363f917599a7fa99f042d5a8"}, - {file = "numpy-1.23.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c67b833dbccefe97cdd3f52798d430b9d3430396af7cdb2a0c32954c3ef73894"}, - {file = "numpy-1.23.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f76025acc8e2114bb664294a07ede0727aa75d63a06d2fae96bf29a81747e4a7"}, - {file = "numpy-1.23.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12ac457b63ec8ded85d85c1e17d85efd3c2b0967ca39560b307a35a6703a4735"}, - {file = "numpy-1.23.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95de7dc7dc47a312f6feddd3da2500826defdccbc41608d0031276a24181a2c0"}, - {file = "numpy-1.23.4-cp39-cp39-win32.whl", hash = "sha256:f2f390aa4da44454db40a1f0201401f9036e8d578a25f01a6e237cea238337ef"}, - {file = "numpy-1.23.4-cp39-cp39-win_amd64.whl", hash = "sha256:f260da502d7441a45695199b4e7fd8ca87db659ba1c78f2bbf31f934fe76ae0e"}, - {file = "numpy-1.23.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:61be02e3bf810b60ab74e81d6d0d36246dbfb644a462458bb53b595791251911"}, - {file = "numpy-1.23.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:296d17aed51161dbad3c67ed6d164e51fcd18dbcd5dd4f9d0a9c6055dce30810"}, - {file = "numpy-1.23.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4d52914c88b4930dafb6c48ba5115a96cbab40f45740239d9f4159c4ba779962"}, - {file = "numpy-1.23.4.tar.gz", hash = "sha256:ed2cc92af0efad20198638c69bb0fc2870a58dabfba6eb722c933b48556c686c"}, -] +myst-nb = [] +myst-parser = [] +nbclassic = [] +nbclient = [] +nbconvert = [] +nbdime = [] +nbformat = [] +nest-asyncio = [] +networkx = [] +ninja = [] +nodeenv = [] +notebook = [] +notebook-shim = [] +numpy = [] packaging = [ {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, ] -pandas = [ - {file = "pandas-1.5.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0a78e05ec09731c5b3bd7a9805927ea631fe6f6cb06f0e7c63191a9a778d52b4"}, - {file = "pandas-1.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5b0c970e2215572197b42f1cff58a908d734503ea54b326412c70d4692256391"}, - {file = "pandas-1.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f340331a3f411910adfb4bbe46c2ed5872d9e473a783d7f14ecf49bc0869c594"}, - {file = "pandas-1.5.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8c709f4700573deb2036d240d140934df7e852520f4a584b2a8d5443b71f54d"}, - {file = "pandas-1.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32e3d9f65606b3f6e76555bfd1d0b68d94aff0929d82010b791b6254bf5a4b96"}, - {file = "pandas-1.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:a52419d9ba5906db516109660b114faf791136c94c1a636ed6b29cbfff9187ee"}, - {file = "pandas-1.5.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:66a1ad667b56e679e06ba73bb88c7309b3f48a4c279bd3afea29f65a766e9036"}, - {file = "pandas-1.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:36aa1f8f680d7584e9b572c3203b20d22d697c31b71189322f16811d4ecfecd3"}, - {file = "pandas-1.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bcf1a82b770b8f8c1e495b19a20d8296f875a796c4fe6e91da5ef107f18c5ecb"}, - {file = "pandas-1.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c25e5c16ee5c0feb6cf9d982b869eec94a22ddfda9aa2fbed00842cbb697624"}, - {file = "pandas-1.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:932d2d7d3cab44cfa275601c982f30c2d874722ef6396bb539e41e4dc4618ed4"}, - {file = "pandas-1.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:eb7e8cf2cf11a2580088009b43de84cabbf6f5dae94ceb489f28dba01a17cb77"}, - {file = "pandas-1.5.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:cb2a9cf1150302d69bb99861c5cddc9c25aceacb0a4ef5299785d0f5389a3209"}, - {file = "pandas-1.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:81f0674fa50b38b6793cd84fae5d67f58f74c2d974d2cb4e476d26eee33343d0"}, - {file = "pandas-1.5.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:17da7035d9e6f9ea9cdc3a513161f8739b8f8489d31dc932bc5a29a27243f93d"}, - {file = "pandas-1.5.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:669c8605dba6c798c1863157aefde959c1796671ffb342b80fcb80a4c0bc4c26"}, - {file = "pandas-1.5.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:683779e5728ac9138406c59a11e09cd98c7d2c12f0a5fc2b9c5eecdbb4a00075"}, - {file = "pandas-1.5.1-cp38-cp38-win32.whl", hash = "sha256:ddf46b940ef815af4e542697eaf071f0531449407a7607dd731bf23d156e20a7"}, - {file = "pandas-1.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:db45b94885000981522fb92349e6b76f5aee0924cc5315881239c7859883117d"}, - {file = "pandas-1.5.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:927e59c694e039c75d7023465d311277a1fc29ed7236b5746e9dddf180393113"}, - {file = "pandas-1.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e675f8fe9aa6c418dc8d3aac0087b5294c1a4527f1eacf9fe5ea671685285454"}, - {file = "pandas-1.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:04e51b01d5192499390c0015630975f57836cc95c7411415b499b599b05c0c96"}, - {file = "pandas-1.5.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cee0c74e93ed4f9d39007e439debcaadc519d7ea5c0afc3d590a3a7b2edf060"}, - {file = "pandas-1.5.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b156a971bc451c68c9e1f97567c94fd44155f073e3bceb1b0d195fd98ed12048"}, - {file = "pandas-1.5.1-cp39-cp39-win32.whl", hash = "sha256:05c527c64ee02a47a24031c880ee0ded05af0623163494173204c5b72ddce658"}, - {file = "pandas-1.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:6bb391659a747cf4f181a227c3e64b6d197100d53da98dcd766cc158bdd9ec68"}, - {file = "pandas-1.5.1.tar.gz", hash = "sha256:249cec5f2a5b22096440bd85c33106b6102e0672204abd2d5c014106459804ee"}, -] -pandas-stubs = [ - {file = "pandas-stubs-1.5.1.221024.tar.gz", hash = "sha256:a756ea4c7f2f973b9f9dfd64d724ba911e82e8ffa2e0188f56fadfdd9345771a"}, - {file = "pandas_stubs-1.5.1.221024-py3-none-any.whl", hash = "sha256:363e3833137375aebd6ab272fe89d94e88a443891a48d536c905e16ce2800cf6"}, -] -pandocfilters = [ - {file = "pandocfilters-1.5.0-py2.py3-none-any.whl", hash = "sha256:33aae3f25fd1a026079f5d27bdd52496f0e0803b3469282162bafdcbdf6ef14f"}, - {file = "pandocfilters-1.5.0.tar.gz", hash = "sha256:0b679503337d233b4339a817bfc8c50064e2eff681314376a47cb582305a7a38"}, -] -parso = [ - {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, - {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, -] -pathspec = [ - {file = "pathspec-0.10.1-py3-none-any.whl", hash = "sha256:46846318467efc4556ccfd27816e004270a9eeeeb4d062ce5e6fc7a87c573f93"}, - {file = "pathspec-0.10.1.tar.gz", hash = "sha256:7ace6161b621d31e7902eb6b5ae148d12cfd23f4a249b9ffb6b9fee12084323d"}, -] -pexpect = [ - {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, - {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, -] -pickleshare = [ - {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, - {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, -] -pillow = [ - {file = "Pillow-9.2.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:a9c9bc489f8ab30906d7a85afac4b4944a572a7432e00698a7239f44a44e6efb"}, - {file = "Pillow-9.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:510cef4a3f401c246cfd8227b300828715dd055463cdca6176c2e4036df8bd4f"}, - {file = "Pillow-9.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7888310f6214f19ab2b6df90f3f06afa3df7ef7355fc025e78a3044737fab1f5"}, - {file = "Pillow-9.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:831e648102c82f152e14c1a0938689dbb22480c548c8d4b8b248b3e50967b88c"}, - {file = "Pillow-9.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1cc1d2451e8a3b4bfdb9caf745b58e6c7a77d2e469159b0d527a4554d73694d1"}, - {file = "Pillow-9.2.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:136659638f61a251e8ed3b331fc6ccd124590eeff539de57c5f80ef3a9594e58"}, - {file = "Pillow-9.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:6e8c66f70fb539301e064f6478d7453e820d8a2c631da948a23384865cd95544"}, - {file = "Pillow-9.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:37ff6b522a26d0538b753f0b4e8e164fdada12db6c6f00f62145d732d8a3152e"}, - {file = "Pillow-9.2.0-cp310-cp310-win32.whl", hash = "sha256:c79698d4cd9318d9481d89a77e2d3fcaeff5486be641e60a4b49f3d2ecca4e28"}, - {file = "Pillow-9.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:254164c57bab4b459f14c64e93df11eff5ded575192c294a0c49270f22c5d93d"}, - {file = "Pillow-9.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:adabc0bce035467fb537ef3e5e74f2847c8af217ee0be0455d4fec8adc0462fc"}, - {file = "Pillow-9.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:336b9036127eab855beec9662ac3ea13a4544a523ae273cbf108b228ecac8437"}, - {file = "Pillow-9.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50dff9cc21826d2977ef2d2a205504034e3a4563ca6f5db739b0d1026658e004"}, - {file = "Pillow-9.2.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cb6259196a589123d755380b65127ddc60f4c64b21fc3bb46ce3a6ea663659b0"}, - {file = "Pillow-9.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b0554af24df2bf96618dac71ddada02420f946be943b181108cac55a7a2dcd4"}, - {file = "Pillow-9.2.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:15928f824870535c85dbf949c09d6ae7d3d6ac2d6efec80f3227f73eefba741c"}, - {file = "Pillow-9.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:bdd0de2d64688ecae88dd8935012c4a72681e5df632af903a1dca8c5e7aa871a"}, - {file = "Pillow-9.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d5b87da55a08acb586bad5c3aa3b86505f559b84f39035b233d5bf844b0834b1"}, - {file = "Pillow-9.2.0-cp311-cp311-win32.whl", hash = "sha256:b6d5e92df2b77665e07ddb2e4dbd6d644b78e4c0d2e9272a852627cdba0d75cf"}, - {file = "Pillow-9.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6bf088c1ce160f50ea40764f825ec9b72ed9da25346216b91361eef8ad1b8f8c"}, - {file = "Pillow-9.2.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:2c58b24e3a63efd22554c676d81b0e57f80e0a7d3a5874a7e14ce90ec40d3069"}, - {file = "Pillow-9.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eef7592281f7c174d3d6cbfbb7ee5984a671fcd77e3fc78e973d492e9bf0eb3f"}, - {file = "Pillow-9.2.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dcd7b9c7139dc8258d164b55696ecd16c04607f1cc33ba7af86613881ffe4ac8"}, - {file = "Pillow-9.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a138441e95562b3c078746a22f8fca8ff1c22c014f856278bdbdd89ca36cff1b"}, - {file = "Pillow-9.2.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:93689632949aff41199090eff5474f3990b6823404e45d66a5d44304e9cdc467"}, - {file = "Pillow-9.2.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:f3fac744f9b540148fa7715a435d2283b71f68bfb6d4aae24482a890aed18b59"}, - {file = "Pillow-9.2.0-cp37-cp37m-win32.whl", hash = "sha256:fa768eff5f9f958270b081bb33581b4b569faabf8774726b283edb06617101dc"}, - {file = "Pillow-9.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:69bd1a15d7ba3694631e00df8de65a8cb031911ca11f44929c97fe05eb9b6c1d"}, - {file = "Pillow-9.2.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:030e3460861488e249731c3e7ab59b07c7853838ff3b8e16aac9561bb345da14"}, - {file = "Pillow-9.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:74a04183e6e64930b667d321524e3c5361094bb4af9083db5c301db64cd341f3"}, - {file = "Pillow-9.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d33a11f601213dcd5718109c09a52c2a1c893e7461f0be2d6febc2879ec2402"}, - {file = "Pillow-9.2.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fd6f5e3c0e4697fa7eb45b6e93996299f3feee73a3175fa451f49a74d092b9f"}, - {file = "Pillow-9.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a647c0d4478b995c5e54615a2e5360ccedd2f85e70ab57fbe817ca613d5e63b8"}, - {file = "Pillow-9.2.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:4134d3f1ba5f15027ff5c04296f13328fecd46921424084516bdb1b2548e66ff"}, - {file = "Pillow-9.2.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:bc431b065722a5ad1dfb4df354fb9333b7a582a5ee39a90e6ffff688d72f27a1"}, - {file = "Pillow-9.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:1536ad017a9f789430fb6b8be8bf99d2f214c76502becc196c6f2d9a75b01b76"}, - {file = "Pillow-9.2.0-cp38-cp38-win32.whl", hash = "sha256:2ad0d4df0f5ef2247e27fc790d5c9b5a0af8ade9ba340db4a73bb1a4a3e5fb4f"}, - {file = "Pillow-9.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:ec52c351b35ca269cb1f8069d610fc45c5bd38c3e91f9ab4cbbf0aebc136d9c8"}, - {file = "Pillow-9.2.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0ed2c4ef2451de908c90436d6e8092e13a43992f1860275b4d8082667fbb2ffc"}, - {file = "Pillow-9.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ad2f835e0ad81d1689f1b7e3fbac7b01bb8777d5a985c8962bedee0cc6d43da"}, - {file = "Pillow-9.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea98f633d45f7e815db648fd7ff0f19e328302ac36427343e4432c84432e7ff4"}, - {file = "Pillow-9.2.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7761afe0126d046974a01e030ae7529ed0ca6a196de3ec6937c11df0df1bc91c"}, - {file = "Pillow-9.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a54614049a18a2d6fe156e68e188da02a046a4a93cf24f373bffd977e943421"}, - {file = "Pillow-9.2.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:5aed7dde98403cd91d86a1115c78d8145c83078e864c1de1064f52e6feb61b20"}, - {file = "Pillow-9.2.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:13b725463f32df1bfeacbf3dd197fb358ae8ebcd8c5548faa75126ea425ccb60"}, - {file = "Pillow-9.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:808add66ea764ed97d44dda1ac4f2cfec4c1867d9efb16a33d158be79f32b8a4"}, - {file = "Pillow-9.2.0-cp39-cp39-win32.whl", hash = "sha256:337a74fd2f291c607d220c793a8135273c4c2ab001b03e601c36766005f36885"}, - {file = "Pillow-9.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:fac2d65901fb0fdf20363fbd345c01958a742f2dc62a8dd4495af66e3ff502a4"}, - {file = "Pillow-9.2.0-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:ad2277b185ebce47a63f4dc6302e30f05762b688f8dc3de55dbae4651872cdf3"}, - {file = "Pillow-9.2.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c7b502bc34f6e32ba022b4a209638f9e097d7a9098104ae420eb8186217ebbb"}, - {file = "Pillow-9.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d1f14f5f691f55e1b47f824ca4fdcb4b19b4323fe43cc7bb105988cad7496be"}, - {file = "Pillow-9.2.0-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:dfe4c1fedfde4e2fbc009d5ad420647f7730d719786388b7de0999bf32c0d9fd"}, - {file = "Pillow-9.2.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:f07f1f00e22b231dd3d9b9208692042e29792d6bd4f6639415d2f23158a80013"}, - {file = "Pillow-9.2.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1802f34298f5ba11d55e5bb09c31997dc0c6aed919658dfdf0198a2fe75d5490"}, - {file = "Pillow-9.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17d4cafe22f050b46d983b71c707162d63d796a1235cdf8b9d7a112e97b15bac"}, - {file = "Pillow-9.2.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:96b5e6874431df16aee0c1ba237574cb6dff1dcb173798faa6a9d8b399a05d0e"}, - {file = "Pillow-9.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:0030fdbd926fb85844b8b92e2f9449ba89607231d3dd597a21ae72dc7fe26927"}, - {file = "Pillow-9.2.0.tar.gz", hash = "sha256:75e636fd3e0fb872693f23ccb8a5ff2cd578801251f3a4f6854c6a5d437d3c04"}, -] -platformdirs = [ - {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, - {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, -] +pandas = [] +pandas-stubs = [] +pandocfilters = [] +parso = [] +pathspec = [] +pexpect = [] +pickleshare = [] +pillow = [] +platformdirs = [] pluggy = [ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ] -pre-commit = [ - {file = "pre_commit-2.20.0-py2.py3-none-any.whl", hash = "sha256:51a5ba7c480ae8072ecdb6933df22d2f812dc897d5fe848778116129a681aac7"}, - {file = "pre_commit-2.20.0.tar.gz", hash = "sha256:a978dac7bc9ec0bcee55c18a277d553b0f419d259dadb4b9418ff2d00eb43959"}, -] -prometheus-client = [ - {file = "prometheus_client-0.15.0-py3-none-any.whl", hash = "sha256:db7c05cbd13a0f79975592d112320f2605a325969b270a94b71dcabc47b931d2"}, - {file = "prometheus_client-0.15.0.tar.gz", hash = "sha256:be26aa452490cfcf6da953f9436e95a9f2b4d578ca80094b4458930e5f584ab1"}, -] -prompt-toolkit = [ - {file = "prompt_toolkit-3.0.31-py3-none-any.whl", hash = "sha256:9696f386133df0fc8ca5af4895afe5d78f5fcfe5258111c2a79a1c3e41ffa96d"}, - {file = "prompt_toolkit-3.0.31.tar.gz", hash = "sha256:9ada952c9d1787f52ff6d5f3484d0b4df8952787c087edf6a1f7c2cb1ea88148"}, -] -psutil = [ - {file = "psutil-5.9.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b4a247cd3feaae39bb6085fcebf35b3b8ecd9b022db796d89c8f05067ca28e71"}, - {file = "psutil-5.9.3-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:5fa88e3d5d0b480602553d362c4b33a63e0c40bfea7312a7bf78799e01e0810b"}, - {file = "psutil-5.9.3-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:767ef4fa33acda16703725c0473a91e1832d296c37c63896c7153ba81698f1ab"}, - {file = "psutil-5.9.3-cp27-cp27m-win32.whl", hash = "sha256:9a4af6ed1094f867834f5f07acd1250605a0874169a5fcadbcec864aec2496a6"}, - {file = "psutil-5.9.3-cp27-cp27m-win_amd64.whl", hash = "sha256:fa5e32c7d9b60b2528108ade2929b115167fe98d59f89555574715054f50fa31"}, - {file = "psutil-5.9.3-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:fe79b4ad4836e3da6c4650cb85a663b3a51aef22e1a829c384e18fae87e5e727"}, - {file = "psutil-5.9.3-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:db8e62016add2235cc87fb7ea000ede9e4ca0aa1f221b40cef049d02d5d2593d"}, - {file = "psutil-5.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:941a6c2c591da455d760121b44097781bc970be40e0e43081b9139da485ad5b7"}, - {file = "psutil-5.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:71b1206e7909792d16933a0d2c1c7f04ae196186c51ba8567abae1d041f06dcb"}, - {file = "psutil-5.9.3-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f57d63a2b5beaf797b87024d018772439f9d3103a395627b77d17a8d72009543"}, - {file = "psutil-5.9.3-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7507f6c7b0262d3e7b0eeda15045bf5881f4ada70473b87bc7b7c93b992a7d7"}, - {file = "psutil-5.9.3-cp310-cp310-win32.whl", hash = "sha256:1b540599481c73408f6b392cdffef5b01e8ff7a2ac8caae0a91b8222e88e8f1e"}, - {file = "psutil-5.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:547ebb02031fdada635452250ff39942db8310b5c4a8102dfe9384ee5791e650"}, - {file = "psutil-5.9.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d8c3cc6bb76492133474e130a12351a325336c01c96a24aae731abf5a47fe088"}, - {file = "psutil-5.9.3-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07d880053c6461c9b89cd5d4808f3b8336665fa3acdefd6777662c5ed73a851a"}, - {file = "psutil-5.9.3-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e8b50241dd3c2ed498507f87a6602825073c07f3b7e9560c58411c14fe1e1c9"}, - {file = "psutil-5.9.3-cp36-cp36m-win32.whl", hash = "sha256:828c9dc9478b34ab96be75c81942d8df0c2bb49edbb481f597314d92b6441d89"}, - {file = "psutil-5.9.3-cp36-cp36m-win_amd64.whl", hash = "sha256:ed15edb14f52925869250b1375f0ff58ca5c4fa8adefe4883cfb0737d32f5c02"}, - {file = "psutil-5.9.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d266cd05bd4a95ca1c2b9b5aac50d249cf7c94a542f47e0b22928ddf8b80d1ef"}, - {file = "psutil-5.9.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e4939ff75149b67aef77980409f156f0082fa36accc475d45c705bb00c6c16a"}, - {file = "psutil-5.9.3-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68fa227c32240c52982cb931801c5707a7f96dd8927f9102d6c7771ea1ff5698"}, - {file = "psutil-5.9.3-cp37-cp37m-win32.whl", hash = "sha256:beb57d8a1ca0ae0eb3d08ccaceb77e1a6d93606f0e1754f0d60a6ebd5c288837"}, - {file = "psutil-5.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:12500d761ac091f2426567f19f95fd3f15a197d96befb44a5c1e3cbe6db5752c"}, - {file = "psutil-5.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba38cf9984d5462b506e239cf4bc24e84ead4b1d71a3be35e66dad0d13ded7c1"}, - {file = "psutil-5.9.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:46907fa62acaac364fff0b8a9da7b360265d217e4fdeaca0a2397a6883dffba2"}, - {file = "psutil-5.9.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a04a1836894c8279e5e0a0127c0db8e198ca133d28be8a2a72b4db16f6cf99c1"}, - {file = "psutil-5.9.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a4e07611997acf178ad13b842377e3d8e9d0a5bac43ece9bfc22a96735d9a4f"}, - {file = "psutil-5.9.3-cp38-cp38-win32.whl", hash = "sha256:6ced1ad823ecfa7d3ce26fe8aa4996e2e53fb49b7fed8ad81c80958501ec0619"}, - {file = "psutil-5.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:35feafe232d1aaf35d51bd42790cbccb882456f9f18cdc411532902370d660df"}, - {file = "psutil-5.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:538fcf6ae856b5e12d13d7da25ad67f02113c96f5989e6ad44422cb5994ca7fc"}, - {file = "psutil-5.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a3d81165b8474087bb90ec4f333a638ccfd1d69d34a9b4a1a7eaac06648f9fbe"}, - {file = "psutil-5.9.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a7826e68b0cf4ce2c1ee385d64eab7d70e3133171376cac53d7c1790357ec8f"}, - {file = "psutil-5.9.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ec296f565191f89c48f33d9544d8d82b0d2af7dd7d2d4e6319f27a818f8d1cc"}, - {file = "psutil-5.9.3-cp39-cp39-win32.whl", hash = "sha256:9ec95df684583b5596c82bb380c53a603bb051cf019d5c849c47e117c5064395"}, - {file = "psutil-5.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:4bd4854f0c83aa84a5a40d3b5d0eb1f3c128f4146371e03baed4589fe4f3c931"}, - {file = "psutil-5.9.3.tar.gz", hash = "sha256:7ccfcdfea4fc4b0a02ca2c31de7fcd186beb9cff8207800e14ab66f79c773af6"}, -] -ptyprocess = [ - {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, - {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, -] -pure-eval = [ - {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, - {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, -] +pre-commit = [] +prometheus-client = [] +prompt-toolkit = [] +psutil = [] +ptyprocess = [] +pure-eval = [] py = [ {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, ] -pybtex = [ - {file = "pybtex-0.24.0-py2.py3-none-any.whl", hash = "sha256:e1e0c8c69998452fea90e9179aa2a98ab103f3eed894405b7264e517cc2fcc0f"}, - {file = "pybtex-0.24.0.tar.gz", hash = "sha256:818eae35b61733e5c007c3fcd2cfb75ed1bc8b4173c1f70b56cc4c0802d34755"}, -] -pybtex-docutils = [ - {file = "pybtex-docutils-1.0.2.tar.gz", hash = "sha256:43aa353b6d498fd5ac30f0073a98e332d061d34fe619d3d50d1761f8fd4aa016"}, - {file = "pybtex_docutils-1.0.2-py3-none-any.whl", hash = "sha256:6f9e3c25a37bcaac8c4f69513272706ec6253bb708a93d8b4b173f43915ba239"}, -] -pycodestyle = [ - {file = "pycodestyle-2.9.1-py2.py3-none-any.whl", hash = "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"}, - {file = "pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"}, -] +pybtex = [] +pybtex-docutils = [] +pycodestyle = [] pycparser = [ {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, ] -pydantic = [ - {file = "pydantic-1.10.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb6ad4489af1bac6955d38ebcb95079a836af31e4c4f74aba1ca05bb9f6027bd"}, - {file = "pydantic-1.10.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a1f5a63a6dfe19d719b1b6e6106561869d2efaca6167f84f5ab9347887d78b98"}, - {file = "pydantic-1.10.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:352aedb1d71b8b0736c6d56ad2bd34c6982720644b0624462059ab29bd6e5912"}, - {file = "pydantic-1.10.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19b3b9ccf97af2b7519c42032441a891a5e05c68368f40865a90eb88833c2559"}, - {file = "pydantic-1.10.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e9069e1b01525a96e6ff49e25876d90d5a563bc31c658289a8772ae186552236"}, - {file = "pydantic-1.10.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:355639d9afc76bcb9b0c3000ddcd08472ae75318a6eb67a15866b87e2efa168c"}, - {file = "pydantic-1.10.2-cp310-cp310-win_amd64.whl", hash = "sha256:ae544c47bec47a86bc7d350f965d8b15540e27e5aa4f55170ac6a75e5f73b644"}, - {file = "pydantic-1.10.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a4c805731c33a8db4b6ace45ce440c4ef5336e712508b4d9e1aafa617dc9907f"}, - {file = "pydantic-1.10.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d49f3db871575e0426b12e2f32fdb25e579dea16486a26e5a0474af87cb1ab0a"}, - {file = "pydantic-1.10.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37c90345ec7dd2f1bcef82ce49b6235b40f282b94d3eec47e801baf864d15525"}, - {file = "pydantic-1.10.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b5ba54d026c2bd2cb769d3468885f23f43710f651688e91f5fb1edcf0ee9283"}, - {file = "pydantic-1.10.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:05e00dbebbe810b33c7a7362f231893183bcc4251f3f2ff991c31d5c08240c42"}, - {file = "pydantic-1.10.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2d0567e60eb01bccda3a4df01df677adf6b437958d35c12a3ac3e0f078b0ee52"}, - {file = "pydantic-1.10.2-cp311-cp311-win_amd64.whl", hash = "sha256:c6f981882aea41e021f72779ce2a4e87267458cc4d39ea990729e21ef18f0f8c"}, - {file = "pydantic-1.10.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c4aac8e7103bf598373208f6299fa9a5cfd1fc571f2d40bf1dd1955a63d6eeb5"}, - {file = "pydantic-1.10.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a7b66c3f499108b448f3f004801fcd7d7165fb4200acb03f1c2402da73ce4c"}, - {file = "pydantic-1.10.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bedf309630209e78582ffacda64a21f96f3ed2e51fbf3962d4d488e503420254"}, - {file = "pydantic-1.10.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9300fcbebf85f6339a02c6994b2eb3ff1b9c8c14f502058b5bf349d42447dcf5"}, - {file = "pydantic-1.10.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:216f3bcbf19c726b1cc22b099dd409aa371f55c08800bcea4c44c8f74b73478d"}, - {file = "pydantic-1.10.2-cp37-cp37m-win_amd64.whl", hash = "sha256:dd3f9a40c16daf323cf913593083698caee97df2804aa36c4b3175d5ac1b92a2"}, - {file = "pydantic-1.10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b97890e56a694486f772d36efd2ba31612739bc6f3caeee50e9e7e3ebd2fdd13"}, - {file = "pydantic-1.10.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9cabf4a7f05a776e7793e72793cd92cc865ea0e83a819f9ae4ecccb1b8aa6116"}, - {file = "pydantic-1.10.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06094d18dd5e6f2bbf93efa54991c3240964bb663b87729ac340eb5014310624"}, - {file = "pydantic-1.10.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc78cc83110d2f275ec1970e7a831f4e371ee92405332ebfe9860a715f8336e1"}, - {file = "pydantic-1.10.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ee433e274268a4b0c8fde7ad9d58ecba12b069a033ecc4645bb6303c062d2e9"}, - {file = "pydantic-1.10.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7c2abc4393dea97a4ccbb4ec7d8658d4e22c4765b7b9b9445588f16c71ad9965"}, - {file = "pydantic-1.10.2-cp38-cp38-win_amd64.whl", hash = "sha256:0b959f4d8211fc964772b595ebb25f7652da3f22322c007b6fed26846a40685e"}, - {file = "pydantic-1.10.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c33602f93bfb67779f9c507e4d69451664524389546bacfe1bee13cae6dc7488"}, - {file = "pydantic-1.10.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5760e164b807a48a8f25f8aa1a6d857e6ce62e7ec83ea5d5c5a802eac81bad41"}, - {file = "pydantic-1.10.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6eb843dcc411b6a2237a694f5e1d649fc66c6064d02b204a7e9d194dff81eb4b"}, - {file = "pydantic-1.10.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b8795290deaae348c4eba0cebb196e1c6b98bdbe7f50b2d0d9a4a99716342fe"}, - {file = "pydantic-1.10.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e0bedafe4bc165ad0a56ac0bd7695df25c50f76961da29c050712596cf092d6d"}, - {file = "pydantic-1.10.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2e05aed07fa02231dbf03d0adb1be1d79cabb09025dd45aa094aa8b4e7b9dcda"}, - {file = "pydantic-1.10.2-cp39-cp39-win_amd64.whl", hash = "sha256:c1ba1afb396148bbc70e9eaa8c06c1716fdddabaf86e7027c5988bae2a829ab6"}, - {file = "pydantic-1.10.2-py3-none-any.whl", hash = "sha256:1b6ee725bd6e83ec78b1aa32c5b1fa67a3a65badddde3976bca5fe4568f27709"}, - {file = "pydantic-1.10.2.tar.gz", hash = "sha256:91b8e218852ef6007c2b98cd861601c6a09f1aa32bbbb74fab5b1c33d4a1e410"}, -] -pydata-sphinx-theme = [ - {file = "pydata_sphinx_theme-0.8.1-py3-none-any.whl", hash = "sha256:af2c99cb0b43d95247b1563860942ba75d7f1596360594fce510caaf8c4fcc16"}, - {file = "pydata_sphinx_theme-0.8.1.tar.gz", hash = "sha256:96165702253917ece13dd895e23b96ee6dce422dcc144d560806067852fe1fed"}, -] -pydot = [ - {file = "pydot-1.4.2-py2.py3-none-any.whl", hash = "sha256:66c98190c65b8d2e2382a441b4c0edfdb4f4c025ef9cb9874de478fb0793a451"}, - {file = "pydot-1.4.2.tar.gz", hash = "sha256:248081a39bcb56784deb018977e428605c1c758f10897a339fce1dd728ff007d"}, -] -pyflakes = [ - {file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"}, - {file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"}, -] -pygments = [ - {file = "Pygments-2.13.0-py3-none-any.whl", hash = "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42"}, - {file = "Pygments-2.13.0.tar.gz", hash = "sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1"}, -] +pydantic = [] +pydata-sphinx-theme = [] +pydot = [] +pyflakes = [] +pygments = [] pyparsing = [ {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, ] -pyrsistent = [ - {file = "pyrsistent-0.18.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:df46c854f490f81210870e509818b729db4488e1f30f2a1ce1698b2295a878d1"}, - {file = "pyrsistent-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d45866ececf4a5fff8742c25722da6d4c9e180daa7b405dc0a2a2790d668c26"}, - {file = "pyrsistent-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4ed6784ceac462a7d6fcb7e9b663e93b9a6fb373b7f43594f9ff68875788e01e"}, - {file = "pyrsistent-0.18.1-cp310-cp310-win32.whl", hash = "sha256:e4f3149fd5eb9b285d6bfb54d2e5173f6a116fe19172686797c056672689daf6"}, - {file = "pyrsistent-0.18.1-cp310-cp310-win_amd64.whl", hash = "sha256:636ce2dc235046ccd3d8c56a7ad54e99d5c1cd0ef07d9ae847306c91d11b5fec"}, - {file = "pyrsistent-0.18.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e92a52c166426efbe0d1ec1332ee9119b6d32fc1f0bbfd55d5c1088070e7fc1b"}, - {file = "pyrsistent-0.18.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7a096646eab884bf8bed965bad63ea327e0d0c38989fc83c5ea7b8a87037bfc"}, - {file = "pyrsistent-0.18.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cdfd2c361b8a8e5d9499b9082b501c452ade8bbf42aef97ea04854f4a3f43b22"}, - {file = "pyrsistent-0.18.1-cp37-cp37m-win32.whl", hash = "sha256:7ec335fc998faa4febe75cc5268a9eac0478b3f681602c1f27befaf2a1abe1d8"}, - {file = "pyrsistent-0.18.1-cp37-cp37m-win_amd64.whl", hash = "sha256:6455fc599df93d1f60e1c5c4fe471499f08d190d57eca040c0ea182301321286"}, - {file = "pyrsistent-0.18.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fd8da6d0124efa2f67d86fa70c851022f87c98e205f0594e1fae044e7119a5a6"}, - {file = "pyrsistent-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bfe2388663fd18bd8ce7db2c91c7400bf3e1a9e8bd7d63bf7e77d39051b85ec"}, - {file = "pyrsistent-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e3e1fcc45199df76053026a51cc59ab2ea3fc7c094c6627e93b7b44cdae2c8c"}, - {file = "pyrsistent-0.18.1-cp38-cp38-win32.whl", hash = "sha256:b568f35ad53a7b07ed9b1b2bae09eb15cdd671a5ba5d2c66caee40dbf91c68ca"}, - {file = "pyrsistent-0.18.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1b96547410f76078eaf66d282ddca2e4baae8964364abb4f4dcdde855cd123a"}, - {file = "pyrsistent-0.18.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f87cc2863ef33c709e237d4b5f4502a62a00fab450c9e020892e8e2ede5847f5"}, - {file = "pyrsistent-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bc66318fb7ee012071b2792024564973ecc80e9522842eb4e17743604b5e045"}, - {file = "pyrsistent-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:914474c9f1d93080338ace89cb2acee74f4f666fb0424896fcfb8d86058bf17c"}, - {file = "pyrsistent-0.18.1-cp39-cp39-win32.whl", hash = "sha256:1b34eedd6812bf4d33814fca1b66005805d3640ce53140ab8bbb1e2651b0d9bc"}, - {file = "pyrsistent-0.18.1-cp39-cp39-win_amd64.whl", hash = "sha256:e24a828f57e0c337c8d8bb9f6b12f09dfdf0273da25fda9e314f0b684b415a07"}, - {file = "pyrsistent-0.18.1.tar.gz", hash = "sha256:d4d61f8b993a7255ba714df3aca52700f8125289f84f704cf80916517c46eb96"}, -] -pytest = [ - {file = "pytest-7.2.0-py3-none-any.whl", hash = "sha256:892f933d339f068883b6fd5a459f03d85bfcb355e4981e146d2c7616c21fef71"}, - {file = "pytest-7.2.0.tar.gz", hash = "sha256:c4014eb40e10f11f355ad4e3c2fb2c6c6d1919c73f3b5a433de4708202cade59"}, -] -pytest-cov = [ - {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, - {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, -] -python-dateutil = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, -] -pytype = [ - {file = "pytype-2022.10.26-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:d6f6d3f1a325b5ce11ed88d5a5a3bde5bab7cfda7436655b618f3b20eb99458f"}, - {file = "pytype-2022.10.26-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f70daa442733574770c85dd141184dc8dc59fff05e2fd60fd034b447398abd38"}, - {file = "pytype-2022.10.26-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6624b26942cb01ffd1cdd4a7cdf679301eeb57d1f7d35c91e858115712972e34"}, - {file = "pytype-2022.10.26-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:37baa29bc6a47bebf4c6be92b69695011e4d1fcfb93350bf37171c38961e5b4b"}, - {file = "pytype-2022.10.26-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bd098ad5e9aefe52d2ca64d1e18603bea4f5052f913b1c7baf1f512d41b7047"}, - {file = "pytype-2022.10.26-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1425453b8d9fb30753057d8822fc2fef1a98072f2614165455f33a896da816b"}, - {file = "pytype-2022.10.26-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:ef0420cae26be4f3f18ec426ace175ee6e62c162093a619165cc684333452c2e"}, - {file = "pytype-2022.10.26-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e03d39ed1fed30160f0e020ffec4b431beab773848da2f2392c431a1035078a2"}, - {file = "pytype-2022.10.26-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70cfc2c09654e05833b9f35234b62eb2d84f94edcdfac6291a539b6b638bc29a"}, - {file = "pytype-2022.10.26-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:9bda3cd816ba0bcc07e1f18dbe5918ec6d237a89ef74a5dc9cacb0b43266f140"}, - {file = "pytype-2022.10.26-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09092519a7c3eb71f0a039ae48caed7feb45a1d129786e5e639f67effee65220"}, - {file = "pytype-2022.10.26-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b426e96414667f9b13a231f2c5e68bc4b6556bd7481ad45f02b6e25a55e33fc2"}, - {file = "pytype-2022.10.26.tar.gz", hash = "sha256:cb3d53319ada918a089c82c430ef34bcde22b5a473e23b593bb12179bd00104c"}, -] -pytz = [ - {file = "pytz-2022.5-py2.py3-none-any.whl", hash = "sha256:335ab46900b1465e714b4fda4963d87363264eb662aab5e65da039c25f1f5b22"}, - {file = "pytz-2022.5.tar.gz", hash = "sha256:c4d88f472f54d615e9cd582a5004d1e5f624854a6a27a6211591c251f22a6914"}, -] -pywin32 = [ - {file = "pywin32-304-cp310-cp310-win32.whl", hash = "sha256:3c7bacf5e24298c86314f03fa20e16558a4e4138fc34615d7de4070c23e65af3"}, - {file = "pywin32-304-cp310-cp310-win_amd64.whl", hash = "sha256:4f32145913a2447736dad62495199a8e280a77a0ca662daa2332acf849f0be48"}, - {file = "pywin32-304-cp310-cp310-win_arm64.whl", hash = "sha256:d3ee45adff48e0551d1aa60d2ec066fec006083b791f5c3527c40cd8aefac71f"}, - {file = "pywin32-304-cp311-cp311-win32.whl", hash = "sha256:30c53d6ce44c12a316a06c153ea74152d3b1342610f1b99d40ba2795e5af0269"}, - {file = "pywin32-304-cp311-cp311-win_amd64.whl", hash = "sha256:7ffa0c0fa4ae4077e8b8aa73800540ef8c24530057768c3ac57c609f99a14fd4"}, - {file = "pywin32-304-cp311-cp311-win_arm64.whl", hash = "sha256:cbbe34dad39bdbaa2889a424d28752f1b4971939b14b1bb48cbf0182a3bcfc43"}, - {file = "pywin32-304-cp36-cp36m-win32.whl", hash = "sha256:be253e7b14bc601718f014d2832e4c18a5b023cbe72db826da63df76b77507a1"}, - {file = "pywin32-304-cp36-cp36m-win_amd64.whl", hash = "sha256:de9827c23321dcf43d2f288f09f3b6d772fee11e809015bdae9e69fe13213988"}, - {file = "pywin32-304-cp37-cp37m-win32.whl", hash = "sha256:f64c0377cf01b61bd5e76c25e1480ca8ab3b73f0c4add50538d332afdf8f69c5"}, - {file = "pywin32-304-cp37-cp37m-win_amd64.whl", hash = "sha256:bb2ea2aa81e96eee6a6b79d87e1d1648d3f8b87f9a64499e0b92b30d141e76df"}, - {file = "pywin32-304-cp38-cp38-win32.whl", hash = "sha256:94037b5259701988954931333aafd39cf897e990852115656b014ce72e052e96"}, - {file = "pywin32-304-cp38-cp38-win_amd64.whl", hash = "sha256:ead865a2e179b30fb717831f73cf4373401fc62fbc3455a0889a7ddac848f83e"}, - {file = "pywin32-304-cp39-cp39-win32.whl", hash = "sha256:25746d841201fd9f96b648a248f731c1dec851c9a08b8e33da8b56148e4c65cc"}, - {file = "pywin32-304-cp39-cp39-win_amd64.whl", hash = "sha256:d24a3382f013b21aa24a5cfbfad5a2cd9926610c0affde3e8ab5b3d7dbcf4ac9"}, -] -pywinpty = [ - {file = "pywinpty-2.0.8-cp310-none-win_amd64.whl", hash = "sha256:9cbf89834abc8d4d4c5f295f11e15dd93889a8069db876f2bc10cc64aa4060ac"}, - {file = "pywinpty-2.0.8-cp37-none-win_amd64.whl", hash = "sha256:a2f9a95f3b74262ef73f1be5257c295c8caab1f79f081aa3400ca61c724f9bc6"}, - {file = "pywinpty-2.0.8-cp38-none-win_amd64.whl", hash = "sha256:23389d56258d6a1fbc4b41257bd65e5bdabaf6fde7f30a13806e557ea9ee6865"}, - {file = "pywinpty-2.0.8-cp39-none-win_amd64.whl", hash = "sha256:ea7c1da94eed5ef93e75026c67c60d4dca33ea9a1c212fa89221079a7b463c68"}, - {file = "pywinpty-2.0.8.tar.gz", hash = "sha256:a89b9021c63ef78b1e7d8e14f0fac4748c88a0c2e4f529c84f37f6e72b914280"}, -] +pyrsistent = [] +pytest = [] +pytest-cov = [] +python-dateutil = [] +pytype = [] +pytz = [] +pywin32 = [] +pywinpty = [] pyyaml = [ {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, @@ -3962,13 +2724,6 @@ pyyaml = [ {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, - {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, - {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, @@ -3996,307 +2751,46 @@ pyyaml = [ {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, ] -pyzmq = [ - {file = "pyzmq-24.0.1-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:28b119ba97129d3001673a697b7cce47fe6de1f7255d104c2f01108a5179a066"}, - {file = "pyzmq-24.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bcbebd369493d68162cddb74a9c1fcebd139dfbb7ddb23d8f8e43e6c87bac3a6"}, - {file = "pyzmq-24.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae61446166983c663cee42c852ed63899e43e484abf080089f771df4b9d272ef"}, - {file = "pyzmq-24.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87f7ac99b15270db8d53f28c3c7b968612993a90a5cf359da354efe96f5372b4"}, - {file = "pyzmq-24.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9dca7c3956b03b7663fac4d150f5e6d4f6f38b2462c1e9afd83bcf7019f17913"}, - {file = "pyzmq-24.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8c78bfe20d4c890cb5580a3b9290f700c570e167d4cdcc55feec07030297a5e3"}, - {file = "pyzmq-24.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:48f721f070726cd2a6e44f3c33f8ee4b24188e4b816e6dd8ba542c8c3bb5b246"}, - {file = "pyzmq-24.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:afe1f3bc486d0ce40abb0a0c9adb39aed3bbac36ebdc596487b0cceba55c21c1"}, - {file = "pyzmq-24.0.1-cp310-cp310-win32.whl", hash = "sha256:3e6192dbcefaaa52ed81be88525a54a445f4b4fe2fffcae7fe40ebb58bd06bfd"}, - {file = "pyzmq-24.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:86de64468cad9c6d269f32a6390e210ca5ada568c7a55de8e681ca3b897bb340"}, - {file = "pyzmq-24.0.1-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:838812c65ed5f7c2bd11f7b098d2e5d01685a3f6d1f82849423b570bae698c00"}, - {file = "pyzmq-24.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dfb992dbcd88d8254471760879d48fb20836d91baa90f181c957122f9592b3dc"}, - {file = "pyzmq-24.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7abddb2bd5489d30ffeb4b93a428130886c171b4d355ccd226e83254fcb6b9ef"}, - {file = "pyzmq-24.0.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94010bd61bc168c103a5b3b0f56ed3b616688192db7cd5b1d626e49f28ff51b3"}, - {file = "pyzmq-24.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8242543c522d84d033fe79be04cb559b80d7eb98ad81b137ff7e0a9020f00ace"}, - {file = "pyzmq-24.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ccb94342d13e3bf3ffa6e62f95b5e3f0bc6bfa94558cb37f4b3d09d6feb536ff"}, - {file = "pyzmq-24.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6640f83df0ae4ae1104d4c62b77e9ef39be85ebe53f636388707d532bee2b7b8"}, - {file = "pyzmq-24.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a180dbd5ea5d47c2d3b716d5c19cc3fb162d1c8db93b21a1295d69585bfddac1"}, - {file = "pyzmq-24.0.1-cp311-cp311-win32.whl", hash = "sha256:624321120f7e60336be8ec74a172ae7fba5c3ed5bf787cc85f7e9986c9e0ebc2"}, - {file = "pyzmq-24.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:1724117bae69e091309ffb8255412c4651d3f6355560d9af312d547f6c5bc8b8"}, - {file = "pyzmq-24.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:15975747462ec49fdc863af906bab87c43b2491403ab37a6d88410635786b0f4"}, - {file = "pyzmq-24.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b947e264f0e77d30dcbccbb00f49f900b204b922eb0c3a9f0afd61aaa1cedc3d"}, - {file = "pyzmq-24.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0ec91f1bad66f3ee8c6deb65fa1fe418e8ad803efedd69c35f3b5502f43bd1dc"}, - {file = "pyzmq-24.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:db03704b3506455d86ec72c3358a779e9b1d07b61220dfb43702b7b668edcd0d"}, - {file = "pyzmq-24.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:e7e66b4e403c2836ac74f26c4b65d8ac0ca1eef41dfcac2d013b7482befaad83"}, - {file = "pyzmq-24.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:7a23ccc1083c260fa9685c93e3b170baba45aeed4b524deb3f426b0c40c11639"}, - {file = "pyzmq-24.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:fa0ae3275ef706c0309556061185dd0e4c4cd3b7d6f67ae617e4e677c7a41e2e"}, - {file = "pyzmq-24.0.1-cp36-cp36m-win32.whl", hash = "sha256:f01de4ec083daebf210531e2cca3bdb1608dbbbe00a9723e261d92087a1f6ebc"}, - {file = "pyzmq-24.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:de4217b9eb8b541cf2b7fde4401ce9d9a411cc0af85d410f9d6f4333f43640be"}, - {file = "pyzmq-24.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:78068e8678ca023594e4a0ab558905c1033b2d3e806a0ad9e3094e231e115a33"}, - {file = "pyzmq-24.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77c2713faf25a953c69cf0f723d1b7dd83827b0834e6c41e3fb3bbc6765914a1"}, - {file = "pyzmq-24.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8bb4af15f305056e95ca1bd086239b9ebc6ad55e9f49076d27d80027f72752f6"}, - {file = "pyzmq-24.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0f14cffd32e9c4c73da66db97853a6aeceaac34acdc0fae9e5bbc9370281864c"}, - {file = "pyzmq-24.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0108358dab8c6b27ff6b985c2af4b12665c1bc659648284153ee501000f5c107"}, - {file = "pyzmq-24.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:d66689e840e75221b0b290b0befa86f059fb35e1ee6443bce51516d4d61b6b99"}, - {file = "pyzmq-24.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ae08ac90aa8fa14caafc7a6251bd218bf6dac518b7bff09caaa5e781119ba3f2"}, - {file = "pyzmq-24.0.1-cp37-cp37m-win32.whl", hash = "sha256:8421aa8c9b45ea608c205db9e1c0c855c7e54d0e9c2c2f337ce024f6843cab3b"}, - {file = "pyzmq-24.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:54d8b9c5e288362ec8595c1d98666d36f2070fd0c2f76e2b3c60fbad9bd76227"}, - {file = "pyzmq-24.0.1-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:acbd0a6d61cc954b9f535daaa9ec26b0a60a0d4353c5f7c1438ebc88a359a47e"}, - {file = "pyzmq-24.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:47b11a729d61a47df56346283a4a800fa379ae6a85870d5a2e1e4956c828eedc"}, - {file = "pyzmq-24.0.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abe6eb10122f0d746a0d510c2039ae8edb27bc9af29f6d1b05a66cc2401353ff"}, - {file = "pyzmq-24.0.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:07bec1a1b22dacf718f2c0e71b49600bb6a31a88f06527dfd0b5aababe3fa3f7"}, - {file = "pyzmq-24.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0d945a85b70da97ae86113faf9f1b9294efe66bd4a5d6f82f2676d567338b66"}, - {file = "pyzmq-24.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1b7928bb7580736ffac5baf814097be342ba08d3cfdfb48e52773ec959572287"}, - {file = "pyzmq-24.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b946da90dc2799bcafa682692c1d2139b2a96ec3c24fa9fc6f5b0da782675330"}, - {file = "pyzmq-24.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c8840f064b1fb377cffd3efeaad2b190c14d4c8da02316dae07571252d20b31f"}, - {file = "pyzmq-24.0.1-cp38-cp38-win32.whl", hash = "sha256:4854f9edc5208f63f0841c0c667260ae8d6846cfa233c479e29fdc85d42ebd58"}, - {file = "pyzmq-24.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:42d4f97b9795a7aafa152a36fe2ad44549b83a743fd3e77011136def512e6c2a"}, - {file = "pyzmq-24.0.1-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:52afb0ac962963fff30cf1be775bc51ae083ef4c1e354266ab20e5382057dd62"}, - {file = "pyzmq-24.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8bad8210ad4df68c44ff3685cca3cda448ee46e20d13edcff8909eba6ec01ca4"}, - {file = "pyzmq-24.0.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:dabf1a05318d95b1537fd61d9330ef4313ea1216eea128a17615038859da3b3b"}, - {file = "pyzmq-24.0.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5bd3d7dfd9cd058eb68d9a905dec854f86649f64d4ddf21f3ec289341386c44b"}, - {file = "pyzmq-24.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8012bce6836d3f20a6c9599f81dfa945f433dab4dbd0c4917a6fb1f998ab33d"}, - {file = "pyzmq-24.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c31805d2c8ade9b11feca4674eee2b9cce1fec3e8ddb7bbdd961a09dc76a80ea"}, - {file = "pyzmq-24.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:3104f4b084ad5d9c0cb87445cc8cfd96bba710bef4a66c2674910127044df209"}, - {file = "pyzmq-24.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:df0841f94928f8af9c7a1f0aaaffba1fb74607af023a152f59379c01c53aee58"}, - {file = "pyzmq-24.0.1-cp39-cp39-win32.whl", hash = "sha256:a435ef8a3bd95c8a2d316d6e0ff70d0db524f6037411652803e118871d703333"}, - {file = "pyzmq-24.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:2032d9cb994ce3b4cba2b8dfae08c7e25bc14ba484c770d4d3be33c27de8c45b"}, - {file = "pyzmq-24.0.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bb5635c851eef3a7a54becde6da99485eecf7d068bd885ac8e6d173c4ecd68b0"}, - {file = "pyzmq-24.0.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:83ea1a398f192957cb986d9206ce229efe0ee75e3c6635baff53ddf39bd718d5"}, - {file = "pyzmq-24.0.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:941fab0073f0a54dc33d1a0460cb04e0d85893cb0c5e1476c785000f8b359409"}, - {file = "pyzmq-24.0.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e8f482c44ccb5884bf3f638f29bea0f8dc68c97e38b2061769c4cb697f6140d"}, - {file = "pyzmq-24.0.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:613010b5d17906c4367609e6f52e9a2595e35d5cc27d36ff3f1b6fa6e954d944"}, - {file = "pyzmq-24.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:65c94410b5a8355cfcf12fd600a313efee46ce96a09e911ea92cf2acf6708804"}, - {file = "pyzmq-24.0.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:20e7eeb1166087db636c06cae04a1ef59298627f56fb17da10528ab52a14c87f"}, - {file = "pyzmq-24.0.1-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2712aee7b3834ace51738c15d9ee152cc5a98dc7d57dd93300461b792ab7b43"}, - {file = "pyzmq-24.0.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a7c280185c4da99e0cc06c63bdf91f5b0b71deb70d8717f0ab870a43e376db8"}, - {file = "pyzmq-24.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:858375573c9225cc8e5b49bfac846a77b696b8d5e815711b8d4ba3141e6e8879"}, - {file = "pyzmq-24.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:80093b595921eed1a2cead546a683b9e2ae7f4a4592bb2ab22f70d30174f003a"}, - {file = "pyzmq-24.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f3f3154fde2b1ff3aa7b4f9326347ebc89c8ef425ca1db8f665175e6d3bd42f"}, - {file = "pyzmq-24.0.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abb756147314430bee5d10919b8493c0ccb109ddb7f5dfd2fcd7441266a25b75"}, - {file = "pyzmq-24.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44e706bac34e9f50779cb8c39f10b53a4d15aebb97235643d3112ac20bd577b4"}, - {file = "pyzmq-24.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:687700f8371643916a1d2c61f3fdaa630407dd205c38afff936545d7b7466066"}, - {file = "pyzmq-24.0.1.tar.gz", hash = "sha256:216f5d7dbb67166759e59b0479bca82b8acf9bed6015b526b8eb10143fb08e77"}, -] -requests = [ - {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, - {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, -] -scikit-learn = [ - {file = "scikit-learn-1.1.3.tar.gz", hash = "sha256:bef51978a51ec19977700fe7b86aecea49c825884f3811756b74a3b152bb4e35"}, - {file = "scikit_learn-1.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8e9dd76c7274055d1acf4526b8efb16a3531c26dcda714a0c16da99bf9d41900"}, - {file = "scikit_learn-1.1.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ee47f68d973cee7009f06edb956f2f5588a0f230f24a2a70175fd0ecf36e2653"}, - {file = "scikit_learn-1.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da5a2e95fef9805b1750e4abda4e834bf8835d26fc709a391543b53feee7bd0e"}, - {file = "scikit_learn-1.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:701181792a28c82fecae12adb5d15d0ecf57bffab7cf4bdbb52c7b3fd428d540"}, - {file = "scikit_learn-1.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:30e27721adc308e8fd9f419f43068e43490005f911edf4476a9e585059fa8a83"}, - {file = "scikit_learn-1.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5699cded6c0685426433c7e5afe0fecad80ec831ec7fa264940e50c796775cc5"}, - {file = "scikit_learn-1.1.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:2ee2c649f2231b68511aabb0dc827edd8936aad682acc6263c34aed11bc95dac"}, - {file = "scikit_learn-1.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d1c1394e38a3319ace620381f6f23cc807d8780e9915c152449a86fc8f1db21"}, - {file = "scikit_learn-1.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:250da993701da88bf475e7c5746abf1285ea0ae47e4d0917cd13afd6600bb162"}, - {file = "scikit_learn-1.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:fd3ee69d36d42a7dcbb17e355a5653af5fd241a7dfd9133080b3dde8d9e2aafb"}, - {file = "scikit_learn-1.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f5644663987ee221f5d1f47a593271b966c271c236fe05634e6bdc06041b5a2b"}, - {file = "scikit_learn-1.1.3-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:748f2bd632d6993e8918d43f1a26c380aeda4e122a88840d4c3a9af99d4239fe"}, - {file = "scikit_learn-1.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd55c6fbef7608dbce1f22baf289dfcc6eb323247daa3c3542f73d389c724786"}, - {file = "scikit_learn-1.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38814f66285318f2e241305cca545eaa9b4126c65aa5dd78c69371f235f78e2b"}, - {file = "scikit_learn-1.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:f4931f2a6c06e02c6c17a05f8ae397e2545965bc7a0a6cb38c8cd7d4fba8624d"}, - {file = "scikit_learn-1.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6785b8a3093329bf90ac01801be5525551728ae73edb11baa175df660820add4"}, - {file = "scikit_learn-1.1.3-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:28b2bd6a1419acd522ff45d282c8ba23dbccb5338802ab0ee12baa4ade0aba4c"}, - {file = "scikit_learn-1.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23fb9e74b813cc2528b5167d82ed08950b11106ccf50297161875e45152fb311"}, - {file = "scikit_learn-1.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5d4231af7199531e77da1b78a4cc6b3d960a00b1ec672578ac818aae2b9c35d"}, - {file = "scikit_learn-1.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:4d3a19166d4e1cdfcab975c68f471e046ce01e74c42a9a33fa89a14c2fcedf60"}, -] -scipy = [ - {file = "scipy-1.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1884b66a54887e21addf9c16fb588720a8309a57b2e258ae1c7986d4444d3bc0"}, - {file = "scipy-1.9.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:83b89e9586c62e787f5012e8475fbb12185bafb996a03257e9675cd73d3736dd"}, - {file = "scipy-1.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a72d885fa44247f92743fc20732ae55564ff2a519e8302fb7e18717c5355a8b"}, - {file = "scipy-1.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d01e1dd7b15bd2449c8bfc6b7cc67d630700ed655654f0dfcf121600bad205c9"}, - {file = "scipy-1.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:68239b6aa6f9c593da8be1509a05cb7f9efe98b80f43a5861cd24c7557e98523"}, - {file = "scipy-1.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b41bc822679ad1c9a5f023bc93f6d0543129ca0f37c1ce294dd9d386f0a21096"}, - {file = "scipy-1.9.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:90453d2b93ea82a9f434e4e1cba043e779ff67b92f7a0e85d05d286a3625df3c"}, - {file = "scipy-1.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83c06e62a390a9167da60bedd4575a14c1f58ca9dfde59830fc42e5197283dab"}, - {file = "scipy-1.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abaf921531b5aeaafced90157db505e10345e45038c39e5d9b6c7922d68085cb"}, - {file = "scipy-1.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:06d2e1b4c491dc7d8eacea139a1b0b295f74e1a1a0f704c375028f8320d16e31"}, - {file = "scipy-1.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5a04cd7d0d3eff6ea4719371cbc44df31411862b9646db617c99718ff68d4840"}, - {file = "scipy-1.9.3-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:545c83ffb518094d8c9d83cce216c0c32f8c04aaf28b92cc8283eda0685162d5"}, - {file = "scipy-1.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d54222d7a3ba6022fdf5773931b5d7c56efe41ede7f7128c7b1637700409108"}, - {file = "scipy-1.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cff3a5295234037e39500d35316a4c5794739433528310e117b8a9a0c76d20fc"}, - {file = "scipy-1.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:2318bef588acc7a574f5bfdff9c172d0b1bf2c8143d9582e05f878e580a3781e"}, - {file = "scipy-1.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d644a64e174c16cb4b2e41dfea6af722053e83d066da7343f333a54dae9bc31c"}, - {file = "scipy-1.9.3-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:da8245491d73ed0a994ed9c2e380fd058ce2fa8a18da204681f2fe1f57f98f95"}, - {file = "scipy-1.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4db5b30849606a95dcf519763dd3ab6fe9bd91df49eba517359e450a7d80ce2e"}, - {file = "scipy-1.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c68db6b290cbd4049012990d7fe71a2abd9ffbe82c0056ebe0f01df8be5436b0"}, - {file = "scipy-1.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:5b88e6d91ad9d59478fafe92a7c757d00c59e3bdc3331be8ada76a4f8d683f58"}, - {file = "scipy-1.9.3.tar.gz", hash = "sha256:fbc5c05c85c1a02be77b1ff591087c83bc44579c6d2bd9fb798bb64ea5e1a027"}, -] -send2trash = [ - {file = "Send2Trash-1.8.0-py3-none-any.whl", hash = "sha256:f20eaadfdb517eaca5ce077640cb261c7d2698385a6a0f072a4a5447fd49fa08"}, - {file = "Send2Trash-1.8.0.tar.gz", hash = "sha256:d2c24762fd3759860a0aff155e45871447ea58d2be6bdd39b5c8f966a0c99c2d"}, -] -setuptools = [ - {file = "setuptools-65.5.0-py3-none-any.whl", hash = "sha256:f62ea9da9ed6289bfe868cd6845968a2c854d1427f8548d52cae02a42b4f0356"}, - {file = "setuptools-65.5.0.tar.gz", hash = "sha256:512e5536220e38146176efb833d4a62aa726b7bbff82cfbc8ba9eaa3996e0b17"}, -] -setuptools-scm = [ - {file = "setuptools_scm-7.0.5-py3-none-any.whl", hash = "sha256:7930f720905e03ccd1e1d821db521bff7ec2ac9cf0ceb6552dd73d24a45d3b02"}, - {file = "setuptools_scm-7.0.5.tar.gz", hash = "sha256:031e13af771d6f892b941adb6ea04545bbf91ebc5ce68c78aaf3fff6e1fb4844"}, -] +pyzmq = [] +requests = [] +scikit-learn = [] +scipy = [] +send2trash = [] +setuptools-scm = [] six = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] -smmap = [ - {file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"}, - {file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"}, -] -sniffio = [ - {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, - {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, -] -snowballstemmer = [ - {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, - {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, -] -soupsieve = [ - {file = "soupsieve-2.3.2.post1-py3-none-any.whl", hash = "sha256:3b2503d3c7084a42b1ebd08116e5f81aadfaea95863628c80a3b774a11b7c759"}, - {file = "soupsieve-2.3.2.post1.tar.gz", hash = "sha256:fc53893b3da2c33de295667a0e19f078c14bf86544af307354de5fcf12a3f30d"}, -] -sphinx = [ - {file = "Sphinx-4.5.0-py3-none-any.whl", hash = "sha256:ebf612653238bcc8f4359627a9b7ce44ede6fdd75d9d30f68255c7383d3a6226"}, - {file = "Sphinx-4.5.0.tar.gz", hash = "sha256:7bf8ca9637a4ee15af412d1a1d9689fec70523a68ca9bb9127c2f3eeb344e2e6"}, -] -sphinx-autodoc-typehints = [ - {file = "sphinx_autodoc_typehints-1.19.1-py3-none-any.whl", hash = "sha256:9be46aeeb1b315eb5df1f3a7cb262149895d16c7d7dcd77b92513c3c3a1e85e6"}, - {file = "sphinx_autodoc_typehints-1.19.1.tar.gz", hash = "sha256:6c841db55e0e9be0483ff3962a2152b60e79306f4288d8c4e7e86ac84486a5ea"}, -] -sphinx-book-theme = [ - {file = "sphinx_book_theme-0.3.3-py3-none-any.whl", hash = "sha256:9685959dbbb492af005165ef1b9229fdd5d5431580ac181578beae3b4d012d91"}, - {file = "sphinx_book_theme-0.3.3.tar.gz", hash = "sha256:0ec36208ff14c6d6bf8aee1f1f8268e0c6e2bfa3cef6e41143312b25275a6217"}, -] -sphinx-comments = [ - {file = "sphinx-comments-0.0.3.tar.gz", hash = "sha256:00170afff27019fad08e421da1ae49c681831fb2759786f07c826e89ac94cf21"}, - {file = "sphinx_comments-0.0.3-py3-none-any.whl", hash = "sha256:1e879b4e9bfa641467f83e3441ac4629225fc57c29995177d043252530c21d00"}, -] -sphinx-copybutton = [ - {file = "sphinx-copybutton-0.5.0.tar.gz", hash = "sha256:a0c059daadd03c27ba750da534a92a63e7a36a7736dcf684f26ee346199787f6"}, - {file = "sphinx_copybutton-0.5.0-py3-none-any.whl", hash = "sha256:9684dec7434bd73f0eea58dda93f9bb879d24bff2d8b187b1f2ec08dfe7b5f48"}, -] -sphinx-design = [ - {file = "sphinx_design-0.1.0-py3-none-any.whl", hash = "sha256:151ab25fda162ded010f0782d1770d014073c3f3fea8e02c45178e0ae6f7e0a0"}, - {file = "sphinx_design-0.1.0.tar.gz", hash = "sha256:68edba2453a175df5b0390d481ec0e9329112064f211860426729768b3501706"}, -] -sphinx-external-toc = [ - {file = "sphinx_external_toc-0.2.4-py3-none-any.whl", hash = "sha256:f7906620e74fbef50f0c3b8adf943da03000ab955ffe957ae4760d6cd5a09717"}, - {file = "sphinx_external_toc-0.2.4.tar.gz", hash = "sha256:f073c482d959a166f844ca8caadd13e24fa43153750cc120646ded37ff622018"}, -] -sphinx-jupyterbook-latex = [ - {file = "sphinx_jupyterbook_latex-0.4.7-py3-none-any.whl", hash = "sha256:616990de4e5680879bede70260dd4f3821586c4c0f36d1b1a1ebb736020a7f92"}, - {file = "sphinx_jupyterbook_latex-0.4.7.tar.gz", hash = "sha256:288640a8d5476e75bc4d88c7b2446d2af385adf8c57e45e6ec27cd3345806b07"}, -] -sphinx-multitoc-numbering = [ - {file = "sphinx-multitoc-numbering-0.1.3.tar.gz", hash = "sha256:c9607671ac511236fa5d61a7491c1031e700e8d498c9d2418e6c61d1251209ae"}, - {file = "sphinx_multitoc_numbering-0.1.3-py3-none-any.whl", hash = "sha256:33d2e707a9b2b8ad636b3d4302e658a008025106fe0474046c651144c26d8514"}, -] -sphinx-thebe = [ - {file = "sphinx-thebe-0.1.2.tar.gz", hash = "sha256:756f1dd6643f5abb491f8a27b22825b04f47e05c5d214bbb2e6b5d42b621b85e"}, - {file = "sphinx_thebe-0.1.2-py3-none-any.whl", hash = "sha256:42bb15287bba3459a1faf6081d1bb7a6a426c77a6ba41ac8d3aa98e8f75baa6b"}, -] -sphinx-togglebutton = [ - {file = "sphinx-togglebutton-0.3.2.tar.gz", hash = "sha256:ab0c8b366427b01e4c89802d5d078472c427fa6e9d12d521c34fa0442559dc7a"}, - {file = "sphinx_togglebutton-0.3.2-py3-none-any.whl", hash = "sha256:9647ba7874b7d1e2d43413d8497153a85edc6ac95a3fea9a75ef9c1e08aaae2b"}, -] -sphinxcontrib-applehelp = [ - {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"}, - {file = "sphinxcontrib_applehelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a"}, -] -sphinxcontrib-bibtex = [ - {file = "sphinxcontrib-bibtex-2.5.0.tar.gz", hash = "sha256:71b42e5db0e2e284f243875326bf9936aa9a763282277d75048826fef5b00eaa"}, - {file = "sphinxcontrib_bibtex-2.5.0-py3-none-any.whl", hash = "sha256:748f726eaca6efff7731012103417ef130ecdcc09501b4d0c54283bf5f059f76"}, -] -sphinxcontrib-devhelp = [ - {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"}, - {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, -] -sphinxcontrib-htmlhelp = [ - {file = "sphinxcontrib-htmlhelp-2.0.0.tar.gz", hash = "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2"}, - {file = "sphinxcontrib_htmlhelp-2.0.0-py2.py3-none-any.whl", hash = "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07"}, -] -sphinxcontrib-jsmath = [ - {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, - {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, -] -sphinxcontrib-qthelp = [ - {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, - {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, -] -sphinxcontrib-serializinghtml = [ - {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"}, - {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"}, -] -sqlalchemy = [ - {file = "SQLAlchemy-1.4.42-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:28e881266a172a4d3c5929182fde6bb6fba22ac93f137d5380cc78a11a9dd124"}, - {file = "SQLAlchemy-1.4.42-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ca9389a00f639383c93ed00333ed763812f80b5ae9e772ea32f627043f8c9c88"}, - {file = "SQLAlchemy-1.4.42-cp27-cp27m-win32.whl", hash = "sha256:1d0c23ecf7b3bc81e29459c34a3f4c68ca538de01254e24718a7926810dc39a6"}, - {file = "SQLAlchemy-1.4.42-cp27-cp27m-win_amd64.whl", hash = "sha256:6c9d004eb78c71dd4d3ce625b80c96a827d2e67af9c0d32b1c1e75992a7916cc"}, - {file = "SQLAlchemy-1.4.42-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9e3a65ce9ed250b2f096f7b559fe3ee92e6605fab3099b661f0397a9ac7c8d95"}, - {file = "SQLAlchemy-1.4.42-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:2e56dfed0cc3e57b2f5c35719d64f4682ef26836b81067ee6cfad062290fd9e2"}, - {file = "SQLAlchemy-1.4.42-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b42c59ffd2d625b28cdb2ae4cde8488543d428cba17ff672a543062f7caee525"}, - {file = "SQLAlchemy-1.4.42-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:22459fc1718785d8a86171bbe7f01b5c9d7297301ac150f508d06e62a2b4e8d2"}, - {file = "SQLAlchemy-1.4.42-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df76e9c60879fdc785a34a82bf1e8691716ffac32e7790d31a98d7dec6e81545"}, - {file = "SQLAlchemy-1.4.42-cp310-cp310-win32.whl", hash = "sha256:e7e740453f0149437c101ea4fdc7eea2689938c5760d7dcc436c863a12f1f565"}, - {file = "SQLAlchemy-1.4.42-cp310-cp310-win_amd64.whl", hash = "sha256:effc89e606165ca55f04f3f24b86d3e1c605e534bf1a96e4e077ce1b027d0b71"}, - {file = "SQLAlchemy-1.4.42-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:97ff50cd85bb907c2a14afb50157d0d5486a4b4639976b4a3346f34b6d1b5272"}, - {file = "SQLAlchemy-1.4.42-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e12c6949bae10f1012ab5c0ea52ab8db99adcb8c7b717938252137cdf694c775"}, - {file = "SQLAlchemy-1.4.42-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11b2ec26c5d2eefbc3e6dca4ec3d3d95028be62320b96d687b6e740424f83b7d"}, - {file = "SQLAlchemy-1.4.42-cp311-cp311-win32.whl", hash = "sha256:6045b3089195bc008aee5c273ec3ba9a93f6a55bc1b288841bd4cfac729b6516"}, - {file = "SQLAlchemy-1.4.42-cp311-cp311-win_amd64.whl", hash = "sha256:0501f74dd2745ec38f44c3a3900fb38b9db1ce21586b691482a19134062bf049"}, - {file = "SQLAlchemy-1.4.42-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:6e39e97102f8e26c6c8550cb368c724028c575ec8bc71afbbf8faaffe2b2092a"}, - {file = "SQLAlchemy-1.4.42-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15d878929c30e41fb3d757a5853b680a561974a0168cd33a750be4ab93181628"}, - {file = "SQLAlchemy-1.4.42-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fa5b7eb2051e857bf83bade0641628efe5a88de189390725d3e6033a1fff4257"}, - {file = "SQLAlchemy-1.4.42-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e1c5f8182b4f89628d782a183d44db51b5af84abd6ce17ebb9804355c88a7b5"}, - {file = "SQLAlchemy-1.4.42-cp36-cp36m-win32.whl", hash = "sha256:a7dd5b7b34a8ba8d181402d824b87c5cee8963cb2e23aa03dbfe8b1f1e417cde"}, - {file = "SQLAlchemy-1.4.42-cp36-cp36m-win_amd64.whl", hash = "sha256:5ede1495174e69e273fad68ad45b6d25c135c1ce67723e40f6cf536cb515e20b"}, - {file = "SQLAlchemy-1.4.42-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:9256563506e040daddccaa948d055e006e971771768df3bb01feeb4386c242b0"}, - {file = "SQLAlchemy-1.4.42-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4948b6c5f4e56693bbeff52f574279e4ff972ea3353f45967a14c30fb7ae2beb"}, - {file = "SQLAlchemy-1.4.42-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1811a0b19a08af7750c0b69e38dec3d46e47c4ec1d74b6184d69f12e1c99a5e0"}, - {file = "SQLAlchemy-1.4.42-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b01d9cd2f9096f688c71a3d0f33f3cd0af8549014e66a7a7dee6fc214a7277d"}, - {file = "SQLAlchemy-1.4.42-cp37-cp37m-win32.whl", hash = "sha256:bd448b262544b47a2766c34c0364de830f7fb0772d9959c1c42ad61d91ab6565"}, - {file = "SQLAlchemy-1.4.42-cp37-cp37m-win_amd64.whl", hash = "sha256:04f2598c70ea4a29b12d429a80fad3a5202d56dce19dd4916cc46a965a5ca2e9"}, - {file = "SQLAlchemy-1.4.42-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:3ab7c158f98de6cb4f1faab2d12973b330c2878d0c6b689a8ca424c02d66e1b3"}, - {file = "SQLAlchemy-1.4.42-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ee377eb5c878f7cefd633ab23c09e99d97c449dd999df639600f49b74725b80"}, - {file = "SQLAlchemy-1.4.42-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:934472bb7d8666727746a75670a1f8d91a9cae8c464bba79da30a0f6faccd9e1"}, - {file = "SQLAlchemy-1.4.42-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb94a3d1ba77ff2ef11912192c066f01e68416f554c194d769391638c8ad09a"}, - {file = "SQLAlchemy-1.4.42-cp38-cp38-win32.whl", hash = "sha256:f0f574465b78f29f533976c06b913e54ab4980b9931b69aa9d306afff13a9471"}, - {file = "SQLAlchemy-1.4.42-cp38-cp38-win_amd64.whl", hash = "sha256:a85723c00a636eed863adb11f1e8aaa36ad1c10089537823b4540948a8429798"}, - {file = "SQLAlchemy-1.4.42-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:5ce6929417d5dce5ad1d3f147db81735a4a0573b8fb36e3f95500a06eaddd93e"}, - {file = "SQLAlchemy-1.4.42-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723e3b9374c1ce1b53564c863d1a6b2f1dc4e97b1c178d9b643b191d8b1be738"}, - {file = "SQLAlchemy-1.4.42-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:876eb185911c8b95342b50a8c4435e1c625944b698a5b4a978ad2ffe74502908"}, - {file = "SQLAlchemy-1.4.42-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fd49af453e590884d9cdad3586415922a8e9bb669d874ee1dc55d2bc425aacd"}, - {file = "SQLAlchemy-1.4.42-cp39-cp39-win32.whl", hash = "sha256:e4ef8cb3c5b326f839bfeb6af5f406ba02ad69a78c7aac0fbeeba994ad9bb48a"}, - {file = "SQLAlchemy-1.4.42-cp39-cp39-win_amd64.whl", hash = "sha256:5f966b64c852592469a7eb759615bbd351571340b8b344f1d3fa2478b5a4c934"}, - {file = "SQLAlchemy-1.4.42.tar.gz", hash = "sha256:177e41914c476ed1e1b77fd05966ea88c094053e17a85303c4ce007f88eff363"}, -] -stack-data = [ - {file = "stack_data-0.5.1-py3-none-any.whl", hash = "sha256:5120731a18ba4c82cefcf84a945f6f3e62319ef413bfc210e32aca3a69310ba2"}, - {file = "stack_data-0.5.1.tar.gz", hash = "sha256:95eb784942e861a3d80efd549ff9af6cf847d88343a12eb681d7157cfcb6e32b"}, -] -starlette = [ - {file = "starlette-0.20.4-py3-none-any.whl", hash = "sha256:c0414d5a56297d37f3db96a84034d61ce29889b9eaccf65eb98a0b39441fcaa3"}, - {file = "starlette-0.20.4.tar.gz", hash = "sha256:42fcf3122f998fefce3e2c5ad7e5edbf0f02cf685d646a83a08d404726af5084"}, -] -tabulate = [ - {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, - {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, -] -terminado = [ - {file = "terminado-0.16.0-py3-none-any.whl", hash = "sha256:3e995072a7178a104c41134548ce9b03e4e7f0a538e9c29df4f1fbc81c7cfc75"}, - {file = "terminado-0.16.0.tar.gz", hash = "sha256:fac14374eb5498bdc157ed32e510b1f60d5c3c7981a9f5ba018bb9a64cec0c25"}, -] -threadpoolctl = [ - {file = "threadpoolctl-3.1.0-py3-none-any.whl", hash = "sha256:8b99adda265feb6773280df41eece7b2e6561b772d21ffd52e372f999024907b"}, - {file = "threadpoolctl-3.1.0.tar.gz", hash = "sha256:a335baacfaa4400ae1f0d8e3a58d6674d2f8828e3716bb2802c44955ad391380"}, -] -tinycss2 = [ - {file = "tinycss2-1.2.1-py3-none-any.whl", hash = "sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847"}, - {file = "tinycss2-1.2.1.tar.gz", hash = "sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627"}, -] -tokenize-rt = [ - {file = "tokenize_rt-5.0.0-py2.py3-none-any.whl", hash = "sha256:c67772c662c6b3dc65edf66808577968fb10badfc2042e3027196bed4daf9e5a"}, - {file = "tokenize_rt-5.0.0.tar.gz", hash = "sha256:3160bc0c3e8491312d0485171dea861fc160a240f5f5766b72a1165408d10740"}, -] +smmap = [] +sniffio = [] +snowballstemmer = [] +soupsieve = [] +sphinx = [] +sphinx-autodoc-typehints = [] +sphinx-book-theme = [] +sphinx-comments = [] +sphinx-copybutton = [] +sphinx-design = [] +sphinx-external-toc = [] +sphinx-jupyterbook-latex = [] +sphinx-multitoc-numbering = [] +sphinx-thebe = [] +sphinx-togglebutton = [] +sphinxcontrib-applehelp = [] +sphinxcontrib-bibtex = [] +sphinxcontrib-devhelp = [] +sphinxcontrib-htmlhelp = [] +sphinxcontrib-jsmath = [] +sphinxcontrib-qthelp = [] +sphinxcontrib-serializinghtml = [] +sqlalchemy = [] +stack-data = [] +starlette = [] +tabulate = [] +terminado = [] +threadpoolctl = [] +tinycss2 = [] +tokenize-rt = [] toml = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, @@ -4305,84 +2799,23 @@ tomli = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] -toolz = [ - {file = "toolz-0.12.0-py3-none-any.whl", hash = "sha256:2059bd4148deb1884bb0eb770a3cde70e7f954cfbbdc2285f1f2de01fd21eb6f"}, - {file = "toolz-0.12.0.tar.gz", hash = "sha256:88c570861c440ee3f2f6037c4654613228ff40c93a6c25e0eba70d17282c6194"}, -] -tornado = [ - {file = "tornado-6.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:20f638fd8cc85f3cbae3c732326e96addff0a15e22d80f049e00121651e82e72"}, - {file = "tornado-6.2-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:87dcafae3e884462f90c90ecc200defe5e580a7fbbb4365eda7c7c1eb809ebc9"}, - {file = "tornado-6.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba09ef14ca9893954244fd872798b4ccb2367c165946ce2dd7376aebdde8e3ac"}, - {file = "tornado-6.2-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8150f721c101abdef99073bf66d3903e292d851bee51910839831caba341a75"}, - {file = "tornado-6.2-cp37-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3a2f5999215a3a06a4fc218026cd84c61b8b2b40ac5296a6db1f1451ef04c1e"}, - {file = "tornado-6.2-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:5f8c52d219d4995388119af7ccaa0bcec289535747620116a58d830e7c25d8a8"}, - {file = "tornado-6.2-cp37-abi3-musllinux_1_1_i686.whl", hash = "sha256:6fdfabffd8dfcb6cf887428849d30cf19a3ea34c2c248461e1f7d718ad30b66b"}, - {file = "tornado-6.2-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:1d54d13ab8414ed44de07efecb97d4ef7c39f7438cf5e976ccd356bebb1b5fca"}, - {file = "tornado-6.2-cp37-abi3-win32.whl", hash = "sha256:5c87076709343557ef8032934ce5f637dbb552efa7b21d08e89ae7619ed0eb23"}, - {file = "tornado-6.2-cp37-abi3-win_amd64.whl", hash = "sha256:e5f923aa6a47e133d1cf87d60700889d7eae68988704e20c75fb2d65677a8e4b"}, - {file = "tornado-6.2.tar.gz", hash = "sha256:9b630419bde84ec666bfd7ea0a4cb2a8a651c2d5cccdbdd1972a0c859dfc3c13"}, -] -traitlets = [ - {file = "traitlets-5.5.0-py3-none-any.whl", hash = "sha256:1201b2c9f76097195989cdf7f65db9897593b0dfd69e4ac96016661bb6f0d30f"}, - {file = "traitlets-5.5.0.tar.gz", hash = "sha256:b122f9ff2f2f6c1709dab289a05555be011c87828e911c0cf4074b85cb780a79"}, -] -types-pkg-resources = [ - {file = "types-pkg_resources-0.1.3.tar.gz", hash = "sha256:834a9b8d3dbea343562fd99d5d3359a726f6bf9d3733bccd2b4f3096fbab9dae"}, - {file = "types_pkg_resources-0.1.3-py2.py3-none-any.whl", hash = "sha256:0cb9972cee992249f93fff1a491bf2dc3ce674e5a1926e27d4f0866f7d9b6d9c"}, -] -types-pytz = [ - {file = "types-pytz-2022.5.0.0.tar.gz", hash = "sha256:0c163b15d3e598e6cc7074a99ca9ec72b25dc1b446acc133b827667af0b7b09a"}, - {file = "types_pytz-2022.5.0.0-py3-none-any.whl", hash = "sha256:a8e1fe6a1b270fbfaf2553b20ad0f1316707cc320e596da903bb17d7373fed2d"}, -] -typing-extensions = [ - {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, - {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, -] -typing-inspect = [ - {file = "typing_inspect-0.8.0-py3-none-any.whl", hash = "sha256:5fbf9c1e65d4fa01e701fe12a5bca6c6e08a4ffd5bc60bfac028253a447c5188"}, - {file = "typing_inspect-0.8.0.tar.gz", hash = "sha256:8b1ff0c400943b6145df8119c41c244ca8207f1f10c9c057aeed1560e4806e3d"}, -] -uc-micro-py = [ - {file = "uc-micro-py-1.0.1.tar.gz", hash = "sha256:b7cdf4ea79433043ddfe2c82210208f26f7962c0cfbe3bacb05ee879a7fdb596"}, - {file = "uc_micro_py-1.0.1-py3-none-any.whl", hash = "sha256:316cfb8b6862a0f1d03540f0ae6e7b033ff1fa0ddbe60c12cbe0d4cec846a69f"}, -] -urllib3 = [ - {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"}, - {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"}, -] -uvicorn = [ - {file = "uvicorn-0.19.0-py3-none-any.whl", hash = "sha256:cc277f7e73435748e69e075a721841f7c4a95dba06d12a72fe9874acced16f6f"}, - {file = "uvicorn-0.19.0.tar.gz", hash = "sha256:cf538f3018536edb1f4a826311137ab4944ed741d52aeb98846f52215de57f25"}, -] -vega-datasets = [ - {file = "vega_datasets-0.9.0-py3-none-any.whl", hash = "sha256:3d7c63917be6ca9b154b565f4779a31fedce57b01b5b9d99d8a34a7608062a1d"}, - {file = "vega_datasets-0.9.0.tar.gz", hash = "sha256:9dbe9834208e8ec32ab44970df315de9102861e4cda13d8e143aab7a80d93fc0"}, -] -virtualenv = [ - {file = "virtualenv-20.16.5-py3-none-any.whl", hash = "sha256:d07dfc5df5e4e0dbc92862350ad87a36ed505b978f6c39609dc489eadd5b0d27"}, - {file = "virtualenv-20.16.5.tar.gz", hash = "sha256:227ea1b9994fdc5ea31977ba3383ef296d7472ea85be9d6732e42a91c04e80da"}, -] +toolz = [] +tornado = [] +traitlets = [] +types-pkg-resources = [] +types-pytz = [] +typing-extensions = [] +typing-inspect = [] +uc-micro-py = [] +urllib3 = [] +uvicorn = [] +vega-datasets = [] +virtualenv = [] wcwidth = [ {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, ] -webencodings = [ - {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, - {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, -] -websocket-client = [ - {file = "websocket-client-1.4.1.tar.gz", hash = "sha256:f9611eb65c8241a67fb373bef040b3cf8ad377a9f6546a12b620b6511e8ea9ef"}, - {file = "websocket_client-1.4.1-py3-none-any.whl", hash = "sha256:398909eb7e261f44b8f4bd474785b6ec5f5b499d4953342fe9755e01ef624090"}, -] -wheel = [ - {file = "wheel-0.37.1-py2.py3-none-any.whl", hash = "sha256:4bdcd7d840138086126cd09254dc6195fb4fc6f01c050a1d7236f2630db1d22a"}, - {file = "wheel-0.37.1.tar.gz", hash = "sha256:e9a504e793efbca1b8e0e9cb979a249cf4a0a7b5b8c9e8b65a5e39d49529c1c4"}, -] -widgetsnbextension = [ - {file = "widgetsnbextension-3.6.1-py2.py3-none-any.whl", hash = "sha256:954e0faefdd414e4e013f17dbc7fd86f24cf1d243a3ac85d5f0fc2c2d2b50c66"}, - {file = "widgetsnbextension-3.6.1.tar.gz", hash = "sha256:9c84ae64c2893c7cbe2eaafc7505221a795c27d68938454034ac487319a75b10"}, -] -zipp = [ - {file = "zipp-3.9.0-py3-none-any.whl", hash = "sha256:972cfa31bc2fedd3fa838a51e9bc7e64b7fb725a8c00e7431554311f180e9980"}, - {file = "zipp-3.9.0.tar.gz", hash = "sha256:3a7af91c3db40ec72dd9d154ae18e008c69efe8ca88dde4f9a731bb82fe2f9eb"}, -] +webencodings = [] +websocket-client = [] +widgetsnbextension = [] +zipp = [] diff --git a/pyproject.toml b/pyproject.toml index d110b140..fdfd3579 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,7 +45,7 @@ ipywidgets = "^7.7.2" isort = "^5.10.1" jupyter-book = "^0.13.1" jupyterlab = "^3.5.0" -mypy = "^0.982" +mypy = "^0.990" pandas-stubs = "^1.5.1" pre-commit = "^2.20.0" pytest = "^7.2.0" From 182c8d15472d19ace3a71226d3beb0480c786174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Thu, 10 Nov 2022 18:03:47 +0100 Subject: [PATCH 08/45] refactor: satisfy type analyzers --- draco/renderer/altair_renderer.py | 74 ++++++++++++++++++------------- draco/types.py | 33 ++++++++------ 2 files changed, 63 insertions(+), 44 deletions(-) diff --git a/draco/renderer/altair_renderer.py b/draco/renderer/altair_renderer.py index e97f686c..ab972f20 100644 --- a/draco/renderer/altair_renderer.py +++ b/draco/renderer/altair_renderer.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import TypeVar +from typing import Generic, TypeVar import altair as alt from pandas import DataFrame @@ -10,69 +10,83 @@ Field, FieldName, Mark, + Scale, SpecificationDict, View, ) from .base_renderer import BaseRenderer -VegaLiteChart = TypeVar("VegaLiteChart", alt.VConcatChart, alt.HConcatChart, alt.Chart) +VegaLiteChart = TypeVar( + "VegaLiteChart", alt.VConcatChart, alt.HConcatChart, alt.FacetChart, alt.Chart +) @dataclass(frozen=True) -class VisitorContext: +class RootContext(Generic[VegaLiteChart]): spec: SpecificationDict - product: VegaLiteChart - views: list[View] | None = None - view: View | None = None - mark: Mark | None = None - encoding: Encoding | None = None + chart: VegaLiteChart + chart_views: list[VegaLiteChart] + + +@dataclass(frozen=True) +class ViewContext(RootContext): + view: View + + +@dataclass(frozen=True) +class MarkContext(ViewContext): + mark: Mark + + +@dataclass(frozen=True) +class EncodingContext(MarkContext): + encoding: Encoding class AltairRenderer(BaseRenderer[VegaLiteChart]): def build(self, spec: SpecificationDict, data: DataFrame) -> VegaLiteChart: chart = alt.Chart(data) - views = [] + chart_views: list[VegaLiteChart] = [] for v in spec.view: for m in v.mark: chart = self.__visit_mark( - ctx=VisitorContext( - spec=spec, product=chart, views=views, view=v, mark=m + ctx=MarkContext( + spec=spec, chart=chart, chart_views=chart_views, view=v, mark=m ) ) for e in m.encoding: chart = self.__visit_encoding( - ctx=VisitorContext( + ctx=EncodingContext( spec=spec, - product=chart, - views=views, + chart=chart, + chart_views=chart_views, view=v, mark=m, encoding=e, ) ) chart = self.__visit_view( - ctx=VisitorContext(spec=spec, product=chart, views=views, view=v) + ctx=ViewContext(spec=spec, chart=chart, chart_views=chart_views, view=v) ) - views.append(chart) + chart_views.append(chart) return self.__visit_root( - ctx=VisitorContext(spec=spec, product=chart, views=views) + ctx=RootContext(spec=spec, chart=chart, chart_views=chart_views) ) def display(self, product: VegaLiteChart) -> None: pass - def __visit_root(self, ctx: VisitorContext) -> VegaLiteChart: - views = ctx.views + def __visit_root(self, ctx: RootContext) -> VegaLiteChart: + views = ctx.chart_views chart = len(views) > 1 and alt.vconcat(*views) or views[0] - has_shared_scale = ctx.spec.scale is not None - if has_shared_scale: + if ctx.spec.scale is not None: channels = [s.channel for s in ctx.spec.scale] resolve_scale_args = {c: "shared" for c in channels} chart = chart.resolve_scale(**resolve_scale_args) return chart - def __visit_view(self, ctx: VisitorContext) -> VegaLiteChart: - view, chart = (ctx.view, ctx.product) + def __visit_view(self, ctx: ViewContext) -> VegaLiteChart: + view, chart = (ctx.view, ctx.chart) if view.facet is not None: for f in view.facet: channel = f.channel @@ -91,8 +105,8 @@ def __visit_view(self, ctx: VisitorContext) -> VegaLiteChart: raise ValueError(f"Unknown facet channel: {channel}") return chart - def __visit_mark(self, ctx: VisitorContext) -> VegaLiteChart: - chart, mark_type = (ctx.product, ctx.mark.type) + def __visit_mark(self, ctx: MarkContext) -> VegaLiteChart: + chart, mark_type = (ctx.chart, ctx.mark.type) match mark_type: case "point": return chart.mark_point() @@ -111,8 +125,8 @@ def __visit_mark(self, ctx: VisitorContext) -> VegaLiteChart: case _: raise ValueError(f"Unknown mark type: {mark_type}") - def __visit_encoding(self, ctx: VisitorContext) -> VegaLiteChart: - spec, chart, view, encoding = (ctx.spec, ctx.product, ctx.view, ctx.encoding) + def __visit_encoding(self, ctx: EncodingContext) -> VegaLiteChart: + spec, chart, view, encoding = (ctx.spec, ctx.chart, ctx.view, ctx.encoding) custom_args = {} if encoding.field is not None: @@ -122,7 +136,7 @@ def __visit_encoding(self, ctx: VisitorContext) -> VegaLiteChart: custom_args["bin"] = alt.BinParams(maxbins=encoding.binning) if view.scale is not None: - scale_or_none = self.__get_scale_for_encoding(encoding.channel, view) + scale_or_none = self.__get_scale_for_encoding(encoding.channel, view.scale) if scale_or_none is not None: custom_args["scale"] = scale_or_none @@ -160,12 +174,12 @@ def __get_field_type(self, fields: list[Field], field_name: FieldName) -> str: return renames[field_by_name[0].type] def __get_scale_for_encoding( - self, channel: EncodingChannel, view: View + self, channel: EncodingChannel, scales: list[Scale] ) -> alt.Scale | None: renames = { "categorical": "ordinal", } - for scale in view.scale: + for scale in scales: if scale.channel == channel: scale_args = scale.dict(exclude_none=True, exclude={"channel"}) scale_args["type"] = renames.get(scale.type, scale.type) diff --git a/draco/types.py b/draco/types.py index 9348fa7c..41794e8b 100644 --- a/draco/types.py +++ b/draco/types.py @@ -1,13 +1,18 @@ from typing import Iterable, Literal, TypeAlias -import pydantic +# granular imports to satisfy `pyright` +import pydantic.class_validators as pydantic_validators +import pydantic.config as pydantic_config +import pydantic.fields as pydantic_fields +import pydantic.main as pydantic_main +import pydantic.types as pydantic_types Specification: TypeAlias = Iterable[str] | str """ The number of rows in the dataset. """ -DatasetNumberRows = pydantic.PositiveInt +DatasetNumberRows = pydantic_types.PositiveInt """ The name of a data field. @@ -26,13 +31,13 @@ The number of unique values. Described as `(field,unique)` """ -FieldUnique = pydantic.PositiveInt +FieldUnique = pydantic_types.PositiveInt """ The entropy of the field. Described as `(field,entropy)` """ -FieldEntropy = pydantic.PositiveFloat +FieldEntropy = pydantic_types.PositiveFloat """ The minimum value. Only used for numbers. @@ -50,13 +55,13 @@ The standard deviation. Only used for numbers. Described as `(field,std)` """ -FieldStd = pydantic.confloat(ge=0) +FieldStd = float """ The frequency of the most common value. Only used for strings. Described as `(field,freq)` """ -FieldFreq = pydantic.PositiveInt +FieldFreq = pydantic_types.PositiveInt """ When the task regards specific fields, fields can be marked as relevant to the task. @@ -99,7 +104,7 @@ How the data is binned into N bins. Positive integer. Described as `(encoding,binning)` """ -EncodingBinning = pydantic.PositiveInt +EncodingBinning = pydantic_types.PositiveInt """ Stacking strategy. One of zero, center, or normalize. @@ -145,9 +150,9 @@ FacetBinning = EncodingBinning -class SchemaBase(pydantic.BaseModel): +class SchemaBase(pydantic_main.BaseModel): class Config: - extra = pydantic.Extra.forbid + extra = pydantic_config.Extra.forbid class Encoding(SchemaBase): @@ -157,7 +162,7 @@ class Encoding(SchemaBase): binning: EncodingBinning | None = None stack: EncodingStack | None = None - @pydantic.root_validator(pre=True) + @pydantic_validators.root_validator(pre=True) def check_field_is_present_unless_agg_count(cls, values: dict): if values.get("aggregate", None) != "count" and "field" not in values: raise ValueError("field must be present unless aggregate is count") @@ -171,7 +176,7 @@ class Mark(SchemaBase): class Scale(SchemaBase): channel: ScaleChannel - type: ScaleType = pydantic.Field(default="linear") + type: ScaleType = pydantic_fields.Field(default="linear") zero: ScaleZero | None = None @@ -182,7 +187,7 @@ class Facet(SchemaBase): class View(SchemaBase): - coordinates: ViewCoordinate = pydantic.Field(default="cartesian") + coordinates: ViewCoordinate = pydantic_fields.Field(default="cartesian") mark: list[Mark] scale: list[Scale] | None = None facet: list[Facet] | None = None @@ -202,7 +207,7 @@ class Field(SchemaBase): __STRING_ONLY_FIELDS__ = {"freq"} __NUMBER_ONLY_FIELDS__ = {"min", "max", "std"} - @pydantic.root_validator(pre=True) + @pydantic_validators.root_validator(pre=True) def check_no_string_attributes_on_number_type(cls, values: dict): if values["type"] == "number": for field in cls.__STRING_ONLY_FIELDS__: @@ -212,7 +217,7 @@ def check_no_string_attributes_on_number_type(cls, values: dict): ) return values - @pydantic.root_validator(pre=True) + @pydantic_validators.root_validator(pre=True) def check_no_number_attributes_on_string_type(cls, values: dict): if values["type"] == "string": for field in cls.__NUMBER_ONLY_FIELDS__: From 68e65e8ffc4039238470231a7d4e3834c4a9c42e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Thu, 10 Nov 2022 18:52:37 +0100 Subject: [PATCH 09/45] chore: bump `wheel` maybe fixes failing CI job https://github.com/cmudig/draco2/actions/runs/3439166059/jobs/5736131475 --- poetry.lock | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index 5aa90792..7e847ef9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2545,7 +2545,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "flake8 [metadata] lock-version = "1.1" python-versions = ">=3.10.0,<3.11" -content-hash = "6bd63a651208289e631eb60d29596c556e2eab7b8a0647d138245fecb6058bcd" +content-hash = "cee6e279d5d87d8fa8f8c1cbe606276af48b74fbbb712e4a30f22eac6e0b7a99" [metadata.files] alabaster = [] diff --git a/pyproject.toml b/pyproject.toml index fd76a36a..a3a6c0de 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,7 +55,7 @@ sphinx-autodoc-typehints = "^1.19.1" toml = "^0.10.2" types-pkg-resources = "^0.1.2" vega-datasets = "^0.9.0" -wheel = "^0.38.2" +wheel = "^0.38.4" [build-system] requires = ["poetry-core>=1.0.0"] From f15dda8a9b32da7895907aefebc3969b06f58cd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Thu, 10 Nov 2022 22:28:56 +0100 Subject: [PATCH 10/45] docs: document renderer --- draco/renderer/__init__.py | 4 ++ draco/renderer/altair_renderer.py | 84 +++++++++++++++++++++++++++++-- draco/renderer/base_renderer.py | 21 +++++--- 3 files changed, 97 insertions(+), 12 deletions(-) diff --git a/draco/renderer/__init__.py b/draco/renderer/__init__.py index e69de29b..1566a9fc 100644 --- a/draco/renderer/__init__.py +++ b/draco/renderer/__init__.py @@ -0,0 +1,4 @@ +from .altair_renderer import AltairRenderer +from .base_renderer import BaseRenderer + +__all__ = ["BaseRenderer", "AltairRenderer"] diff --git a/draco/renderer/altair_renderer.py b/draco/renderer/altair_renderer.py index ab972f20..e757c198 100644 --- a/draco/renderer/altair_renderer.py +++ b/draco/renderer/altair_renderer.py @@ -16,6 +16,10 @@ ) from .base_renderer import BaseRenderer +""" +Generic parameter for the type of the produced visualization object. +Used to abstract away the final type of the produced visualization object. +""" VegaLiteChart = TypeVar( "VegaLiteChart", alt.VConcatChart, alt.HConcatChart, alt.FacetChart, alt.Chart ) @@ -23,6 +27,11 @@ @dataclass(frozen=True) class RootContext(Generic[VegaLiteChart]): + """ + Visitor callback context available when processing + the dictionary-based specification at the root level. + """ + spec: SpecificationDict chart: VegaLiteChart chart_views: list[VegaLiteChart] @@ -30,23 +39,46 @@ class RootContext(Generic[VegaLiteChart]): @dataclass(frozen=True) class ViewContext(RootContext): + """ + Visitor callback context available when processing + the dictionary-based specification at the `View` level. + """ + view: View @dataclass(frozen=True) class MarkContext(ViewContext): + """ + Visitor callback context available when processing + the dictionary-based specification at the `Mark` level. + """ + mark: Mark @dataclass(frozen=True) class EncodingContext(MarkContext): + """ + Visitor callback context available when processing + the dictionary-based specification at the `Encoding` level. + """ + encoding: Encoding class AltairRenderer(BaseRenderer[VegaLiteChart]): - def build(self, spec: SpecificationDict, data: DataFrame) -> VegaLiteChart: + """ + Produces a `Vega-Lite `_ visualization + represented as an `Altair `_ chart object. + """ + + def render(self, spec: SpecificationDict, data: DataFrame) -> VegaLiteChart: + # initial chart to be mutated by the visitor callbacks chart = alt.Chart(data) chart_views: list[VegaLiteChart] = [] + + # Traverse the specification dict and invoke the appropriate visitor for v in spec.view: for m in v.mark: chart = self.__visit_mark( @@ -73,10 +105,14 @@ def build(self, spec: SpecificationDict, data: DataFrame) -> VegaLiteChart: ctx=RootContext(spec=spec, chart=chart, chart_views=chart_views) ) - def display(self, product: VegaLiteChart) -> None: - pass - def __visit_root(self, ctx: RootContext) -> VegaLiteChart: + """ + Handles root-level configuration. + Responsible for chart concatenation and resolution of shared axes. + + :param ctx: The current visitor context. + :return: The chart with the root configuration applied. + """ views = ctx.chart_views chart = len(views) > 1 and alt.vconcat(*views) or views[0] if ctx.spec.scale is not None: @@ -86,6 +122,14 @@ def __visit_root(self, ctx: RootContext) -> VegaLiteChart: return chart def __visit_view(self, ctx: ViewContext) -> VegaLiteChart: + """ + Handles view-specific configuration. + Responsible for faceting and concatenation. + + :param ctx: The current visitor context. + :return: The chart with the view applied. + :raises ValueError: if the facet channel is not supported + """ view, chart = (ctx.view, ctx.chart) if view.facet is not None: for f in view.facet: @@ -106,6 +150,14 @@ def __visit_view(self, ctx: ViewContext) -> VegaLiteChart: return chart def __visit_mark(self, ctx: MarkContext) -> VegaLiteChart: + """ + Handles mark-specific configuration. + Responsible for applying the mark type to the chart. + + :param ctx: The current visitor context. + :return: The chart with the mark applied. + :raises ValueError: if the mark type is not supported + """ chart, mark_type = (ctx.chart, ctx.mark.type) match mark_type: case "point": @@ -126,6 +178,14 @@ def __visit_mark(self, ctx: MarkContext) -> VegaLiteChart: raise ValueError(f"Unknown mark type: {mark_type}") def __visit_encoding(self, ctx: EncodingContext) -> VegaLiteChart: + """ + Handles encoding-specific configuration. + Responsible for applying the encoding to the chart. + + :param ctx: The current visitor context. + :return: The updated chart. + :raises ValueError: If an unknown encoding channel is encountered. + """ spec, chart, view, encoding = (ctx.spec, ctx.chart, ctx.view, ctx.encoding) custom_args = {} @@ -162,6 +222,15 @@ def __visit_encoding(self, ctx: EncodingContext) -> VegaLiteChart: raise ValueError(f"Unknown channel: {encoding.channel}") def __get_field_type(self, fields: list[Field], field_name: FieldName) -> str: + """ + Returns the type of the field with the given name. + Needed to map from Draco-spec data types to Vega-Lite data types. + + :param fields: list of fields in the specification + :param field_name: name of the field to look up + :return: the type of the field + :raises ValueError: if the field is not found + """ renames = { "number": "quantitative", "string": "nominal", @@ -176,6 +245,13 @@ def __get_field_type(self, fields: list[Field], field_name: FieldName) -> str: def __get_scale_for_encoding( self, channel: EncodingChannel, scales: list[Scale] ) -> alt.Scale | None: + """ + Returns the scale for the given encoding channel, if any. + + :param channel: the channel for which to look up a scale + :param scales: the list of scales in the view + :return: the scale for the given channel, or None if no scale is found + """ renames = { "categorical": "ordinal", } diff --git a/draco/renderer/base_renderer.py b/draco/renderer/base_renderer.py index e6550b8b..f9ed5345 100644 --- a/draco/renderer/base_renderer.py +++ b/draco/renderer/base_renderer.py @@ -9,14 +9,19 @@ class BaseRenderer(ABC, Generic[T]): - @abstractmethod - def build(self, spec: SpecificationDict, data: DataFrame) -> T: - raise NotImplementedError + """ + Base class for all renderers. + Should handle the creation of a visualization + represented as an object of type `T`. + """ @abstractmethod - def display(self, product: T) -> None: - raise NotImplementedError + def render(self, spec: SpecificationDict, data: DataFrame) -> T: + """ + Render a visualization from a dictionary-based specification and data. - def render(self, spec: SpecificationDict, data: DataFrame) -> None: - product = self.build(spec, data) - self.display(product) + :param spec: Specification of the visualization. + :param data: Data to render. + :return: Produced visualization object of type `T`. + """ + raise NotImplementedError From 2630f610f6d3f938d6b03ba46e5e6ad3d9c07a15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Thu, 10 Nov 2022 22:38:23 +0100 Subject: [PATCH 11/45] docs: document `types` --- draco/types.py | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/draco/types.py b/draco/types.py index 41794e8b..a02f1632 100644 --- a/draco/types.py +++ b/draco/types.py @@ -7,6 +7,9 @@ import pydantic.main as pydantic_main import pydantic.types as pydantic_types +""" +ASP-based fact representation of a visualization specification. +""" Specification: TypeAlias = Iterable[str] | str """ @@ -151,11 +154,21 @@ class SchemaBase(pydantic_main.BaseModel): + """Base class for all schema classes.""" + class Config: + # Do not allow fields that are not defined in the schema explicitly. extra = pydantic_config.Extra.forbid class Encoding(SchemaBase): + """ + Encoding schema. + Encodings define how data fields map to visual properties (channel) of the mark. + + `Read More `_. + """ + channel: EncodingChannel field: EncodingField | None = None aggregate: EncodingAggregate | None = None @@ -170,23 +183,54 @@ def check_field_is_present_unless_agg_count(cls, values: dict): class Mark(SchemaBase): + """ + Mark schema. + A mark represents the graphical mark of the visualization. + + `Read More `_. + """ + type: MarkType encoding: list[Encoding] class Scale(SchemaBase): + """ + Scale schema. + Scales map abstract values such as time or temperature to + a visual value such as x- or y-position or color. + + `Read More `_. + """ + channel: ScaleChannel type: ScaleType = pydantic_fields.Field(default="linear") zero: ScaleZero | None = None class Facet(SchemaBase): + """ + Facet schema. + With the facet operator, we can partition a dataset by a field + and create a view for each field. + The resulting chart is often called a small multiples chart. + + `Read More `_. + """ + channel: FacetChannel field: FacetField binning: FacetBinning | None = None class View(SchemaBase): + """ + View schema. + A view can group marks and scales together. + + `Read More `_. + """ + coordinates: ViewCoordinate = pydantic_fields.Field(default="cartesian") mark: list[Mark] scale: list[Scale] | None = None @@ -194,6 +238,14 @@ class View(SchemaBase): class Field(SchemaBase): + """ + Field schema. + Represents a column in the dataset. + Draco can use information about the field type and field statistics. + + `Read More `_. + """ + name: FieldName type: FieldType unique: FieldUnique | None = None @@ -229,6 +281,11 @@ def check_no_number_attributes_on_string_type(cls, values: dict): class SpecificationDict(SchemaBase): + """ + Specification schema. + Describes a visualization completely. + """ + number_rows: DatasetNumberRows field: list[Field] view: list[View] From 9f8162d2556d3e6b5a23c6ba29d6bccbc69b0d2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Thu, 10 Nov 2022 22:52:43 +0100 Subject: [PATCH 12/45] chore: update `poetry.lock` --- poetry.lock | 224 +++++++++++++++++----------------------------------- 1 file changed, 71 insertions(+), 153 deletions(-) diff --git a/poetry.lock b/poetry.lock index 7e847ef9..70409ce9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -180,7 +180,7 @@ webencodings = "*" [package.extras] css = ["tinycss2 (>=1.1.0,<1.2)"] -dev = ["build (==0.8.0)", "flake8 (==4.0.1)", "hashin (==0.17.0)", "pip-tools (==6.6.2)", "pytest (==7.1.2)", "Sphinx (==4.3.2)", "tox (==3.25.0)", "twine (==4.0.1)", "wheel (==0.37.1)", "black (==22.3.0)", "mypy (==0.961)"] +dev = ["build (==0.8.0)", "flake8 (==4.0.1)", "hashin (==0.17.0)", "pip-tools (==6.6.2)", "pytest (==7.1.2)", "Sphinx (==4.3.2)", "tox (==3.25.0)", "twine (==4.0.1)", "wheel (==0.38.4)", "black (==22.3.0)", "mypy (==0.961)"] [[package]] name = "certifi" @@ -769,10 +769,10 @@ nbformat = "*" sqlalchemy = ">=1.3.12,<1.5" [package.extras] -testing = ["nbformat (>=5.1)", "pandas", "sympy", "numpy", "matplotlib", "pytest-regressions", "pytest-cov", "pytest (>=3.6,<4)", "coverage", "ipykernel"] -rtd = ["pydata-sphinx-theme", "sphinx-copybutton", "myst-nb (>=0.7,<1.0)"] -code_style = ["pre-commit (==1.17.0)", "black", "flake8 (>=3.7.0,<3.8.0)"] -cli = ["pyyaml", "tabulate", "click-log", "click-completion", "click"] +cli = ["click", "click-completion", "click-log", "tabulate", "pyyaml"] +code_style = ["flake8 (>=3.7.0,<3.8.0)", "black", "pre-commit (==1.17.0)"] +rtd = ["myst-nb (>=0.7,<1.0)", "sphinx-copybutton", "pydata-sphinx-theme"] +testing = ["ipykernel", "coverage", "pytest (>=3.6,<4)", "pytest-cov", "pytest-regressions", "matplotlib", "numpy", "sympy", "pandas", "nbformat (>=5.1)"] [[package]] name = "jupyter-client" @@ -852,7 +852,7 @@ python-versions = ">=3.7" jupyter-server = ">=1.1" [package.extras] -test = ["pytest", "jupyter-server"] +test = ["jupyter-server", "pytest"] [[package]] name = "jupyter-sphinx" @@ -952,7 +952,7 @@ six = ">=1.4.1" [[package]] name = "libcst" -version = "0.4.8" +version = "0.4.9" description = "A concrete syntax tree with AST-like properties for Python 3.5, 3.6, 3.7, 3.8, 3.9, and 3.10 programs." category = "dev" optional = false @@ -964,7 +964,7 @@ typing-extensions = ">=3.7.4.2" typing-inspect = ">=0.4.0" [package.extras] -dev = ["black (==22.10.0)", "coverage (>=4.5.4)", "fixit (==0.1.1)", "flake8 (>=3.7.8,<5)", "Sphinx (>=5.1.1)", "hypothesis (>=4.36.0)", "hypothesmith (>=0.0.4)", "jupyter (>=1.0.0)", "maturin (>=0.8.3,<0.14)", "nbsphinx (>=0.4.2)", "prompt-toolkit (>=2.0.9)", "setuptools-scm (>=6.0.1)", "sphinx-rtd-theme (>=0.4.3)", "ufmt (==2.0.1)", "usort (==1.0.5)", "setuptools-rust (>=0.12.1)", "slotscheck (>=0.7.1)", "jinja2 (==3.1.2)", "pyre-check (==0.9.9)"] +dev = ["black (==22.10.0)", "coverage (>=4.5.4)", "fixit (==0.1.1)", "flake8 (>=3.7.8,<5)", "Sphinx (>=5.1.1)", "hypothesis (>=4.36.0)", "hypothesmith (>=0.0.4)", "jupyter (>=1.0.0)", "maturin (>=0.8.3,<0.14)", "nbsphinx (>=0.4.2)", "prompt-toolkit (>=2.0.9)", "setuptools-scm (>=6.0.1)", "sphinx-rtd-theme (>=0.4.3)", "ufmt (==2.0.1)", "usort (==1.0.5)", "setuptools-rust (>=1.5.2)", "slotscheck (>=0.7.1)", "jinja2 (==3.1.2)", "pyre-check (==0.9.9)"] [[package]] name = "linkify-it-py" @@ -978,10 +978,10 @@ python-versions = ">=3.6" uc-micro-py = "*" [package.extras] -test = ["pytest-cov", "pytest", "coverage"] -doc = ["myst-parser", "sphinx-book-theme", "sphinx"] -dev = ["black", "flake8", "isort", "pre-commit"] -benchmark = ["pytest-benchmark", "pytest"] +benchmark = ["pytest", "pytest-benchmark"] +dev = ["pre-commit", "isort", "flake8", "black"] +doc = ["sphinx", "sphinx-book-theme", "myst-parser"] +test = ["coverage", "pytest", "pytest-cov"] [[package]] name = "lxml" @@ -1009,12 +1009,12 @@ python-versions = "~=3.6" attrs = ">=19,<22" [package.extras] -testing = ["pytest-regressions", "pytest-cov", "pytest-benchmark (>=3.2,<4.0)", "pytest (>=3.6,<4)", "psutil", "coverage"] -rtd = ["sphinx-book-theme", "sphinx-panels (>=0.4.0,<0.5.0)", "sphinx-copybutton", "sphinx (>=2,<4)", "pyyaml", "myst-nb (==0.13.0a1)"] -plugins = ["mdit-py-plugins"] -linkify = ["linkify-it-py (>=1.0,<2.0)"] -compare = ["panflute (>=1.12,<2.0)", "mistune (>=0.8.4,<0.9.0)", "mistletoe-ebp (>=0.10.0,<0.11.0)", "markdown (>=3.2.2,<3.3.0)", "commonmark (>=0.9.1,<0.10.0)"] code_style = ["pre-commit (==2.6)"] +compare = ["commonmark (>=0.9.1,<0.10.0)", "markdown (>=3.2.2,<3.3.0)", "mistletoe-ebp (>=0.10.0,<0.11.0)", "mistune (>=0.8.4,<0.9.0)", "panflute (>=1.12,<2.0)"] +linkify = ["linkify-it-py (>=1.0,<2.0)"] +plugins = ["mdit-py-plugins"] +rtd = ["myst-nb (==0.13.0a1)", "pyyaml", "sphinx (>=2,<4)", "sphinx-copybutton", "sphinx-panels (>=0.4.0,<0.5.0)", "sphinx-book-theme"] +testing = ["coverage", "psutil", "pytest (>=3.6,<4)", "pytest-benchmark (>=3.2,<4.0)", "pytest-cov", "pytest-regressions"] [[package]] name = "markupsafe" @@ -1075,9 +1075,9 @@ python-versions = "~=3.6" markdown-it-py = ">=1.0,<2.0" [package.extras] -testing = ["pytest-regressions", "pytest-cov", "pytest (>=3.6,<4)", "coverage"] -rtd = ["sphinx-book-theme (>=0.1.0,<0.2.0)", "myst-parser (==0.14.0a3)"] code_style = ["pre-commit (==2.6)"] +rtd = ["myst-parser (==0.14.0a3)", "sphinx-book-theme (>=0.1.0,<0.2.0)"] +testing = ["coverage", "pytest (>=3.6,<4)", "pytest-cov", "pytest-regressions"] [[package]] name = "mistune" @@ -1407,7 +1407,7 @@ python-dateutil = ">=2.8.1" pytz = ">=2020.1" [package.extras] -test = ["pytest-xdist (>=1.31)", "pytest (>=6.0)", "hypothesis (>=5.5.3)"] +test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] [[package]] name = "pandas-stubs" @@ -1653,10 +1653,10 @@ packaging = "*" sphinx = ">=3.5.4,<5" [package.extras] -dev = ["pydata-sphinx-theme", "nox", "pre-commit", "pyyaml"] -coverage = ["pydata-sphinx-theme", "codecov", "pytest-cov"] -test = ["pydata-sphinx-theme", "pytest"] -doc = ["xarray", "numpy", "plotly", "jupyter-sphinx", "sphinx-sitemap", "sphinxext-rediraffe", "pytest-regressions", "pytest", "pandas", "myst-parser", "numpydoc"] +doc = ["numpydoc", "myst-parser", "pandas", "pytest", "pytest-regressions", "sphinxext-rediraffe", "sphinx-sitemap", "jupyter-sphinx", "plotly", "numpy", "xarray"] +test = ["pytest", "pydata-sphinx-theme"] +coverage = ["pytest-cov", "codecov", "pydata-sphinx-theme"] +dev = ["pyyaml", "pre-commit", "nox", "pydata-sphinx-theme"] [[package]] name = "pydot" @@ -2000,9 +2000,9 @@ pyyaml = "*" sphinx = ">=3,<5" [package.extras] -test = ["sphinx-thebe", "pytest-regressions (>=2.0.1,<2.1.0)", "pytest-cov", "pytest (>=6.0.1,<6.1.0)", "myst-nb (>=0.13.2,<0.14.0)", "coverage", "beautifulsoup4 (>=4.6.1,<5)"] -doc = ["sphinxext-opengraph", "sphinxcontrib-youtube", "sphinxcontrib-bibtex (>=2.2,<3.0)", "sphinx-thebe (>=0.1.1)", "sphinx-togglebutton (>=0.2.1)", "sphinx-tabs", "sphinx-copybutton", "sphinx-examples", "sphinx-design", "sphinx (>=4.0,<5.0)", "plotly", "pandas", "nbclient", "myst-nb (>=0.13.2,<0.14.0)", "numpydoc", "matplotlib", "numpy", "folium", "ipywidgets", "ablog (>=0.10.13,<0.11.0)"] code_style = ["pre-commit (>=2.7.0,<2.8.0)"] +doc = ["ablog (>=0.10.13,<0.11.0)", "ipywidgets", "folium", "numpy", "matplotlib", "numpydoc", "myst-nb (>=0.13.2,<0.14.0)", "nbclient", "pandas", "plotly", "sphinx (>=4.0,<5.0)", "sphinx-design", "sphinx-examples", "sphinx-copybutton", "sphinx-tabs", "sphinx-togglebutton (>=0.2.1)", "sphinx-thebe (>=0.1.1)", "sphinxcontrib-bibtex (>=2.2,<3.0)", "sphinxcontrib-youtube", "sphinxext-opengraph"] +test = ["beautifulsoup4 (>=4.6.1,<5)", "coverage", "myst-nb (>=0.13.2,<0.14.0)", "pytest (>=6.0.1,<6.1.0)", "pytest-cov", "pytest-regressions (>=2.0.1,<2.1.0)", "sphinx-thebe"] [[package]] name = "sphinx-comments" @@ -2016,9 +2016,9 @@ python-versions = "*" sphinx = ">=1.8" [package.extras] -testing = ["sphinx-book-theme", "sphinx (>=2)", "pytest-regressions", "pytest", "myst-parser", "beautifulsoup4"] -sphinx = ["myst-parser", "sphinx-book-theme", "sphinx (>=2)"] -code_style = ["pre-commit (==1.17.0)", "black", "flake8 (>=3.7.0,<3.8.0)"] +code_style = ["flake8 (>=3.7.0,<3.8.0)", "black", "pre-commit (==1.17.0)"] +sphinx = ["sphinx (>=2)", "sphinx-book-theme", "myst-parser"] +testing = ["beautifulsoup4", "myst-parser", "pytest", "pytest-regressions", "sphinx (>=2)", "sphinx-book-theme"] [[package]] name = "sphinx-copybutton" @@ -2032,8 +2032,8 @@ python-versions = ">=3.6" sphinx = ">=1.8" [package.extras] -rtd = ["sphinx-book-theme", "myst-nb", "ipython", "sphinx"] code_style = ["pre-commit (==2.12.1)"] +rtd = ["sphinx", "ipython", "myst-nb", "sphinx-book-theme"] [[package]] name = "sphinx-design" @@ -2047,13 +2047,13 @@ python-versions = ">=3.7" sphinx = ">=3,<5" [package.extras] -theme_sbt = ["sphinx-book-theme (>=0.3.0,<0.4.0)"] -theme_rtd = ["sphinx-rtd-theme (>=1.0,<2.0)"] -theme_pydata = ["pydata-sphinx-theme (>=0.8.1,<0.9.0)"] -theme_furo = ["furo (==2022.04.07)"] -testing = ["pytest-regressions", "pytest-cov", "pytest (>=6.2,<7.0)", "myst-parser (>=0.17.0,<0.18.0)"] -rtd = ["myst-parser (>=0.17.0,<0.18.0)"] code_style = ["pre-commit (>=2.12,<3.0)"] +rtd = ["myst-parser (>=0.17.0,<0.18.0)"] +testing = ["myst-parser (>=0.17.0,<0.18.0)", "pytest (>=6.2,<7.0)", "pytest-cov", "pytest-regressions"] +theme_furo = ["furo (==2022.04.07)"] +theme_pydata = ["pydata-sphinx-theme (>=0.8.1,<0.9.0)"] +theme_rtd = ["sphinx-rtd-theme (>=1.0,<2.0)"] +theme_sbt = ["sphinx-book-theme (>=0.3.0,<0.4.0)"] [[package]] name = "sphinx-external-toc" @@ -2070,9 +2070,9 @@ pyyaml = "*" sphinx = ">=3,<5" [package.extras] -testing = ["pytest-regressions", "pytest-cov", "pytest (>=3.6,<4)", "coverage"] -rtd = ["sphinx-book-theme (>=0.0.36)", "myst-parser (>=0.15.0,<0.16.0)"] code_style = ["pre-commit (>=2.12,<3.0)"] +rtd = ["myst-parser (>=0.15.0,<0.16.0)", "sphinx-book-theme (>=0.0.36)"] +testing = ["coverage", "pytest (>=3.6,<4)", "pytest-cov", "pytest-regressions"] [[package]] name = "sphinx-jupyterbook-latex" @@ -2103,9 +2103,9 @@ python-versions = "*" sphinx = ">=3" [package.extras] -testing = ["jupyter-book", "pytest-regressions", "coverage (<5.0)", "pytest-cov (>=2.8,<3.0)", "pytest (>=5.4,<6.0)"] -rtd = ["myst-parser", "sphinx-book-theme", "sphinx (>=3.0)"] -code_style = ["pre-commit (==1.17.0)", "black", "flake8 (>=3.7.0,<3.8.0)"] +code_style = ["flake8 (>=3.7.0,<3.8.0)", "black", "pre-commit (==1.17.0)"] +rtd = ["sphinx (>=3.0)", "sphinx-book-theme", "myst-parser"] +testing = ["pytest (>=5.4,<6.0)", "pytest-cov (>=2.8,<3.0)", "coverage (<5.0)", "pytest-regressions", "jupyter-book"] [[package]] name = "sphinx-thebe" @@ -2119,8 +2119,8 @@ python-versions = "*" sphinx = ">=3.5,<5" [package.extras] -testing = ["beautifulsoup4", "pytest-regressions", "pytest", "matplotlib"] -sphinx = ["sphinx-panels", "sphinx-copybutton", "sphinx-book-theme", "myst-nb", "matplotlib"] +sphinx = ["matplotlib", "myst-nb", "sphinx-book-theme", "sphinx-copybutton", "sphinx-panels"] +testing = ["matplotlib", "pytest", "pytest-regressions", "beautifulsoup4"] [[package]] name = "sphinx-togglebutton" @@ -2135,7 +2135,7 @@ docutils = "*" sphinx = "*" [package.extras] -sphinx = ["sphinx-examples", "sphinx-design", "sphinx-book-theme", "myst-nb", "numpy", "matplotlib"] +sphinx = ["matplotlib", "numpy", "myst-nb", "sphinx-book-theme", "sphinx-design", "sphinx-examples"] [[package]] name = "sphinxcontrib-applehelp" @@ -2146,8 +2146,8 @@ optional = false python-versions = ">=3.5" [package.extras] +lint = ["flake8", "mypy", "docutils-stubs"] test = ["pytest"] -lint = ["docutils-stubs", "mypy", "flake8"] [[package]] name = "sphinxcontrib-bibtex" @@ -2172,8 +2172,8 @@ optional = false python-versions = ">=3.5" [package.extras] +lint = ["flake8", "mypy", "docutils-stubs"] test = ["pytest"] -lint = ["docutils-stubs", "mypy", "flake8"] [[package]] name = "sphinxcontrib-htmlhelp" @@ -2184,8 +2184,8 @@ optional = false python-versions = ">=3.6" [package.extras] -test = ["html5lib", "pytest"] -lint = ["docutils-stubs", "mypy", "flake8"] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest", "html5lib"] [[package]] name = "sphinxcontrib-jsmath" @@ -2196,7 +2196,7 @@ optional = false python-versions = ">=3.5" [package.extras] -test = ["mypy", "flake8", "pytest"] +test = ["pytest", "flake8", "mypy"] [[package]] name = "sphinxcontrib-qthelp" @@ -2207,8 +2207,8 @@ optional = false python-versions = ">=3.5" [package.extras] +lint = ["flake8", "mypy", "docutils-stubs"] test = ["pytest"] -lint = ["docutils-stubs", "mypy", "flake8"] [[package]] name = "sphinxcontrib-serializinghtml" @@ -2219,8 +2219,8 @@ optional = false python-versions = ">=3.5" [package.extras] +lint = ["flake8", "mypy", "docutils-stubs"] test = ["pytest"] -lint = ["docutils-stubs", "mypy", "flake8"] [[package]] name = "sqlalchemy" @@ -2332,8 +2332,8 @@ python-versions = ">=3.7" webencodings = ">=0.4" [package.extras] -test = ["flake8", "isort", "pytest"] -doc = ["sphinx-rtd-theme", "sphinx"] +doc = ["sphinx", "sphinx-rtd-theme"] +test = ["pytest", "isort", "flake8"] [[package]] name = "tokenize-rt" @@ -2432,7 +2432,7 @@ optional = false python-versions = ">=3.6" [package.extras] -test = ["pytest-cov", "pytest", "coverage"] +test = ["coverage", "pytest", "pytest-cov"] [[package]] name = "urllib3" @@ -2555,10 +2555,7 @@ appnope = [] argon2-cffi = [] argon2-cffi-bindings = [] asttokens = [] -attrs = [ - {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, - {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, -] +attrs = [] babel = [] backcall = [] beautifulsoup4 = [] @@ -2566,15 +2563,9 @@ black = [] bleach = [] certifi = [] cffi = [] -cfgv = [ - {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, - {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, -] +cfgv = [] charset-normalizer = [] -click = [ - {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, - {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, -] +click = [] clingo = [] colorama = [] contourpy = [] @@ -2603,18 +2594,12 @@ idna = [] imagesize = [] importlab = [] importlib-metadata = [] -iniconfig = [ - {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, - {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, -] +iniconfig = [] ipykernel = [] ipython = [] ipython-genutils = [] ipywidgets = [] -isort = [ - {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, - {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, -] +isort = [] jedi = [] jinja2 = [] joblib = [] @@ -2640,17 +2625,11 @@ markdown-it-py = [] markupsafe = [] matplotlib = [] matplotlib-inline = [] -mccabe = [ - {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, - {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, -] +mccabe = [] mdit-py-plugins = [] mistune = [] mypy = [] -mypy-extensions = [ - {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, - {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, -] +mypy-extensions = [] myst-nb = [] myst-parser = [] nbclassic = [] @@ -2665,10 +2644,7 @@ nodeenv = [] notebook = [] notebook-shim = [] numpy = [] -packaging = [ - {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, - {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, -] +packaging = [] pandas = [] pandas-stubs = [] pandocfilters = [] @@ -2678,36 +2654,24 @@ pexpect = [] pickleshare = [] pillow = [] platformdirs = [] -pluggy = [ - {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, - {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, -] +pluggy = [] pre-commit = [] prometheus-client = [] prompt-toolkit = [] psutil = [] ptyprocess = [] pure-eval = [] -py = [ - {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, - {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, -] +py = [] pybtex = [] pybtex-docutils = [] pycodestyle = [] -pycparser = [ - {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, - {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, -] +pycparser = [] pydantic = [] pydata-sphinx-theme = [] pydot = [] pyflakes = [] pygments = [] -pyparsing = [ - {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, - {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, -] +pyparsing = [] pyrsistent = [] pytest = [] pytest-cov = [] @@ -2716,51 +2680,14 @@ pytype = [] pytz = [] pywin32 = [] pywinpty = [] -pyyaml = [ - {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, - {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, - {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, - {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, - {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, - {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, - {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, - {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, - {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, - {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, - {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, - {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, - {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, - {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, - {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, - {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, -] +pyyaml = [] pyzmq = [] requests = [] scikit-learn = [] scipy = [] send2trash = [] setuptools-scm = [] -six = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] +six = [] smmap = [] sniffio = [] snowballstemmer = [] @@ -2791,14 +2718,8 @@ terminado = [] threadpoolctl = [] tinycss2 = [] tokenize-rt = [] -toml = [ - {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, - {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, -] -tomli = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] +toml = [] +tomli = [] toolz = [] tornado = [] traitlets = [] @@ -2811,10 +2732,7 @@ urllib3 = [] uvicorn = [] vega-datasets = [] virtualenv = [] -wcwidth = [ - {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, - {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, -] +wcwidth = [] webencodings = [] websocket-client = [] widgetsnbextension = [] From fc686091fa85e4326e4373c32e112ce6d80376c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Thu, 10 Nov 2022 23:20:36 +0100 Subject: [PATCH 13/45] chore: downgrade `wheel` --- poetry.lock | 4 ++-- pyproject.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index 70409ce9..6e33d305 100644 --- a/poetry.lock +++ b/poetry.lock @@ -180,7 +180,7 @@ webencodings = "*" [package.extras] css = ["tinycss2 (>=1.1.0,<1.2)"] -dev = ["build (==0.8.0)", "flake8 (==4.0.1)", "hashin (==0.17.0)", "pip-tools (==6.6.2)", "pytest (==7.1.2)", "Sphinx (==4.3.2)", "tox (==3.25.0)", "twine (==4.0.1)", "wheel (==0.38.4)", "black (==22.3.0)", "mypy (==0.961)"] +dev = ["build (==0.8.0)", "flake8 (==4.0.1)", "hashin (==0.17.0)", "pip-tools (==6.6.2)", "pytest (==7.1.2)", "Sphinx (==4.3.2)", "tox (==3.25.0)", "twine (==4.0.1)", "wheel (==0.37.1)", "black (==22.3.0)", "mypy (==0.961)"] [[package]] name = "certifi" @@ -2545,7 +2545,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "flake8 [metadata] lock-version = "1.1" python-versions = ">=3.10.0,<3.11" -content-hash = "cee6e279d5d87d8fa8f8c1cbe606276af48b74fbbb712e4a30f22eac6e0b7a99" +content-hash = "3c160a6de624434570bc5bd9c05a7a20546f998880cb4e718428651712ec52ee" [metadata.files] alabaster = [] diff --git a/pyproject.toml b/pyproject.toml index a3a6c0de..1a262c82 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,7 +55,7 @@ sphinx-autodoc-typehints = "^1.19.1" toml = "^0.10.2" types-pkg-resources = "^0.1.2" vega-datasets = "^0.9.0" -wheel = "^0.38.4" +wheel = "^0.37.1" [build-system] requires = ["poetry-core>=1.0.0"] From 2c9cac736478893f0f8a1b99cb93f0b75a39521f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Thu, 10 Nov 2022 23:49:05 +0100 Subject: [PATCH 14/45] test: test `types` cover validators --- draco/tests/test_types.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 draco/tests/test_types.py diff --git a/draco/tests/test_types.py b/draco/tests/test_types.py new file mode 100644 index 00000000..e34b1783 --- /dev/null +++ b/draco/tests/test_types.py @@ -0,0 +1,38 @@ +import pytest + +import draco.types as draco_types + + +@pytest.mark.parametrize( + "data, is_valid", + [ + (dict(channel="x", field="temp"), True), + (dict(channel="x", field="temp", aggregate="mean"), True), + (dict(channel="x", field="temp", aggregate="count"), True), + (dict(channel="x", aggregate="count"), True), + (dict(channel="x", aggregate="mean"), False), + ], +) +def test_encoding_validator(data: dict, is_valid: bool): + if is_valid: + draco_types.Encoding(**data) + else: + with pytest.raises(ValueError): + draco_types.Encoding(**data) + + +@pytest.mark.parametrize( + "data, is_valid", + [ + (dict(name="temp", type="number"), True), + (dict(name="temp", type="number", min=-20, max=50, std=0), True), + (dict(name="temp", type="number", min=-20, max=50, std=0, freq=100), False), + (dict(name="temp", type="string", min=-20, max=50, std=0), False), + ], +) +def test_field_validator(data: dict, is_valid: bool): + if is_valid: + draco_types.Field(**data) + else: + with pytest.raises(ValueError): + draco_types.Field(**data) From 1da11b66606c01be208cf684071115056185c9ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Fri, 11 Nov 2022 00:16:55 +0100 Subject: [PATCH 15/45] refactor: remove unused utility method --- draco/utils.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/draco/utils.py b/draco/utils.py index 3c4b400b..b3b79c9b 100644 --- a/draco/utils.py +++ b/draco/utils.py @@ -3,9 +3,3 @@ def dict_union(*args: dict): return dict(chain.from_iterable(d.items() for d in args)) - - -def dict_value_by_path(d: dict, path: tuple): - for key in path: - d = d[key] - return d From d7a789ea18f363a1c4493fdee9e713d82578d2b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Fri, 11 Nov 2022 00:33:29 +0100 Subject: [PATCH 16/45] test: increase renderer coverage --- draco/renderer/base_renderer.py | 2 +- draco/tests/renderer/__init__.py | 0 draco/tests/renderer/test_altair_renderer.py | 209 +++++++++++++++++++ 3 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 draco/tests/renderer/__init__.py create mode 100644 draco/tests/renderer/test_altair_renderer.py diff --git a/draco/renderer/base_renderer.py b/draco/renderer/base_renderer.py index f9ed5345..58109418 100644 --- a/draco/renderer/base_renderer.py +++ b/draco/renderer/base_renderer.py @@ -24,4 +24,4 @@ def render(self, spec: SpecificationDict, data: DataFrame) -> T: :param data: Data to render. :return: Produced visualization object of type `T`. """ - raise NotImplementedError + raise NotImplementedError # pragma: no cover diff --git a/draco/tests/renderer/__init__.py b/draco/tests/renderer/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/draco/tests/renderer/test_altair_renderer.py b/draco/tests/renderer/test_altair_renderer.py new file mode 100644 index 00000000..9e466a13 --- /dev/null +++ b/draco/tests/renderer/test_altair_renderer.py @@ -0,0 +1,209 @@ +import random + +import pandas as pd +import pytest + +from draco.renderer import AltairRenderer +from draco.types import SpecificationDict + +NUM_ROWS = 100 +df = pd.DataFrame( + { + "temperature": [random.uniform(1, 44) for _ in range(NUM_ROWS)], + "wind": [random.uniform(0, 100) for _ in range(NUM_ROWS)], + "precipitation": [random.uniform(0, 100) for _ in range(NUM_ROWS)], + "condition": random.choices( + ["drizzle", "fog", "rain", "sun", "snow"], k=NUM_ROWS + ), + } +) + + +def data(fields): + return { + "number_rows": 100, + "field": [ + x + for x in [ + {"name": "temperature", "type": "number"}, + {"name": "wind", "type": "number"}, + {"name": "precipitation", "type": "number"}, + {"name": "condition", "type": "string"}, + ] + if x["name"] in fields + ], + } + + +@pytest.fixture +def renderer(): + return AltairRenderer() + + +def vl_specs_equal(a: dict, b: dict) -> bool: + keys_to_remove = {"config", "datasets", "data", "$schema"} + for key in keys_to_remove: + a.pop(key, None) + b.pop(key, None) + return a == b + + +def build_spec(*args): + dct = {} + for arg in args: + dct.update(arg) + return SpecificationDict.parse_obj(dct) + + +# https://dig.cmu.edu/draco2/facts/examples.html#tick-plot +tick_spec_d = build_spec( + data(["temperature"]), + { + "view": [ + { + "mark": [ + { + "type": "tick", + "encoding": [{"channel": "x", "field": "temperature"}], + } + ], + "scale": [{"channel": "x", "type": "linear"}], + } + ] + }, +) +tick_spec_vl = { + "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", + "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, + "encoding": { + "x": { + "field": "temperature", + "scale": {"type": "linear"}, + "type": "quantitative", + } + }, + "mark": "tick", +} + +# https://dig.cmu.edu/draco2/facts/examples.html#tick-plot-with-a-log-scale +tick_log_spec_d = build_spec( + data(["temperature"]), + { + "view": [ + { + "mark": [ + { + "type": "tick", + "encoding": [{"channel": "x", "field": "temperature"}], + } + ], + "scale": [{"channel": "x", "type": "log"}], + } + ] + }, +) +tick_log_spec_vl = { + "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", + "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, + "encoding": { + "x": {"field": "temperature", "scale": {"type": "log"}, "type": "quantitative"} + }, + "mark": "tick", +} + +# https://dig.cmu.edu/draco2/facts/examples.html#bar-chart +bar_spec_d = build_spec( + data(["condition", "temperature"]), + { + "view": [ + { + "coordinates": "cartesian", + "mark": [ + { + "type": "bar", + "encoding": [ + {"channel": "x", "field": "condition"}, + { + "channel": "y", + "field": "temperature", + "aggregate": "mean", + }, + ], + } + ], + "scale": [ + {"channel": "x", "type": "ordinal"}, + {"channel": "y", "type": "linear", "zero": "true"}, + ], + } + ] + }, +) +bar_spec_vl = { + "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", + "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, + "encoding": { + "x": {"field": "condition", "scale": {"type": "ordinal"}, "type": "nominal"}, + "y": { + "aggregate": "mean", + "field": "temperature", + "scale": {"type": "linear", "zero": True}, + "type": "quantitative", + }, + }, + "mark": "bar", +} + +histogram_spec_d = build_spec( + data(["condition"]), + { + "view": [ + { + "mark": [ + { + "type": "bar", + "encoding": [ + {"channel": "x", "field": "condition"}, + {"channel": "y", "aggregate": "count"}, + ], + } + ], + "scale": [ + {"channel": "x", "type": "ordinal"}, + {"channel": "y", "type": "linear", "zero": "true"}, + ], + } + ] + }, +) +histogram_spec_vl = { + "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", + "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, + "encoding": { + "x": {"field": "condition", "scale": {"type": "ordinal"}, "type": "nominal"}, + "y": { + "aggregate": "count", + "field": "condition", + "scale": {"type": "linear", "zero": True}, + "type": "nominal", + }, + }, + "mark": "bar", +} + + +@pytest.mark.parametrize( + "spec, expected_vl", + [ + (tick_spec_d, tick_spec_vl), + (tick_log_spec_d, tick_log_spec_vl), + (bar_spec_d, bar_spec_vl), + # (histogram_spec_d, histogram_spec_vl), + ], +) +def test_single_view_single_mark( + spec: SpecificationDict, expected_vl: dict, renderer: AltairRenderer +): + chart = renderer.render(spec, df) + vl = chart.to_dict() + assert vl_specs_equal(vl, expected_vl) From 2831d86fa56123a82fe6af3bbb261b6af10a7561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Sat, 12 Nov 2022 13:36:01 +0100 Subject: [PATCH 17/45] chore: add `deepdiff` as dev dep Aids VL-renderer debugging --- poetry.lock | 29 ++++++++++++++++++++++++++++- pyproject.toml | 1 + 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 6e33d305..d571ecf9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -306,6 +306,20 @@ category = "dev" optional = false python-versions = ">=3.5" +[[package]] +name = "deepdiff" +version = "6.2.1" +description = "Deep Difference and Search of any Python object/data. Recreate objects by adding adding deltas to each other." +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +ordered-set = ">=4.0.2,<4.2.0" + +[package.extras] +cli = ["click (==8.1.3)", "pyyaml (==6.0)", "toml (==0.10.2)", "clevercsv (==0.7.4)"] + [[package]] name = "defusedxml" version = "0.7.1" @@ -1382,6 +1396,17 @@ category = "main" optional = false python-versions = ">=3.8" +[[package]] +name = "ordered-set" +version = "4.1.0" +description = "An OrderedSet is a custom MutableSet that remembers its order, so that every" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.extras] +dev = ["pytest", "black", "mypy"] + [[package]] name = "packaging" version = "21.3" @@ -2545,7 +2570,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "flake8 [metadata] lock-version = "1.1" python-versions = ">=3.10.0,<3.11" -content-hash = "3c160a6de624434570bc5bd9c05a7a20546f998880cb4e718428651712ec52ee" +content-hash = "5182e9f632f70d0dd754ea95fde40cd44d0c692b1d2eef3543f4d6e8ebd3060f" [metadata.files] alabaster = [] @@ -2573,6 +2598,7 @@ coverage = [] cycler = [] debugpy = [] decorator = [] +deepdiff = [] defusedxml = [] distlib = [] docutils = [] @@ -2644,6 +2670,7 @@ nodeenv = [] notebook = [] notebook-shim = [] numpy = [] +ordered-set = [] packaging = [] pandas = [] pandas-stubs = [] diff --git a/pyproject.toml b/pyproject.toml index 1a262c82..053887c0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,6 +56,7 @@ toml = "^0.10.2" types-pkg-resources = "^0.1.2" vega-datasets = "^0.9.0" wheel = "^0.37.1" +deepdiff = "^6.2.1" [build-system] requires = ["poetry-core>=1.0.0"] From 56926dca5c26c61b406634538a77491c8fb38f77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Sat, 12 Nov 2022 13:52:17 +0100 Subject: [PATCH 18/45] test: use `DeepDiff` in `vl_specs_equal` --- draco/tests/renderer/test_altair_renderer.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/draco/tests/renderer/test_altair_renderer.py b/draco/tests/renderer/test_altair_renderer.py index 9e466a13..7fcd9f3f 100644 --- a/draco/tests/renderer/test_altair_renderer.py +++ b/draco/tests/renderer/test_altair_renderer.py @@ -2,6 +2,7 @@ import pandas as pd import pytest +from deepdiff import DeepDiff from draco.renderer import AltairRenderer from draco.types import SpecificationDict @@ -41,11 +42,14 @@ def renderer(): def vl_specs_equal(a: dict, b: dict) -> bool: - keys_to_remove = {"config", "datasets", "data", "$schema"} - for key in keys_to_remove: - a.pop(key, None) - b.pop(key, None) - return a == b + exclude_from_comparison = {"config", "datasets", "data", "$schema"} + diff = DeepDiff( + a, + b, + exclude_paths=exclude_from_comparison, + ignore_order=True, + ) + return not diff def build_spec(*args): @@ -183,9 +187,7 @@ def build_spec(*args): "x": {"field": "condition", "scale": {"type": "ordinal"}, "type": "nominal"}, "y": { "aggregate": "count", - "field": "condition", "scale": {"type": "linear", "zero": True}, - "type": "nominal", }, }, "mark": "bar", @@ -198,7 +200,7 @@ def build_spec(*args): (tick_spec_d, tick_spec_vl), (tick_log_spec_d, tick_log_spec_vl), (bar_spec_d, bar_spec_vl), - # (histogram_spec_d, histogram_spec_vl), + (histogram_spec_d, histogram_spec_vl), ], ) def test_single_view_single_mark( From 1f1de2c7efbb1603e7e0a4d6aef7115e859eb3a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Tue, 15 Nov 2022 10:55:41 +0100 Subject: [PATCH 19/45] test: single view - single mark --- draco/tests/renderer/test_altair_renderer.py | 170 +++++++++++++++++++ 1 file changed, 170 insertions(+) diff --git a/draco/tests/renderer/test_altair_renderer.py b/draco/tests/renderer/test_altair_renderer.py index 7fcd9f3f..e782a7c8 100644 --- a/draco/tests/renderer/test_altair_renderer.py +++ b/draco/tests/renderer/test_altair_renderer.py @@ -193,6 +193,172 @@ def build_spec(*args): "mark": "bar", } +binned_histogram_spec_d = build_spec( + data(["temperature"]), + { + "view": [ + { + "mark": [ + { + "type": "bar", + "encoding": [ + {"channel": "x", "field": "temperature", "binning": 10}, + {"channel": "y", "aggregate": "count"}, + ], + } + ], + "scale": [ + { + "channel": "x", + "type": "linear", + }, + {"channel": "y", "type": "linear", "zero": "true"}, + ], + } + ] + }, +) + +binned_histogram_spec_vl = { + "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", + "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, + "encoding": { + "x": { + "bin": {"maxbins": 10}, + "field": "temperature", + "scale": {"type": "linear"}, + "type": "quantitative", + }, + "y": {"aggregate": "count", "scale": {"type": "linear", "zero": True}}, + }, + "mark": "bar", +} + +scatter_spec_d = build_spec( + data(["temperature", "wind"]), + { + "view": [ + { + "mark": [ + { + "type": "point", + "encoding": [ + {"channel": "x", "field": "temperature"}, + {"channel": "y", "field": "wind"}, + ], + } + ], + "scale": [ + {"channel": "x", "type": "linear"}, + {"channel": "y", "type": "linear"}, + ], + } + ] + }, +) + +scatter_spec_vl = { + "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", + "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, + "encoding": { + "x": { + "field": "temperature", + "scale": {"type": "linear"}, + "type": "quantitative", + }, + "y": {"field": "wind", "scale": {"type": "linear"}, "type": "quantitative"}, + }, + "mark": "point", +} + +scatter_with_color_spec_d = build_spec( + data(["temperature", "wind", "condition"]), + { + "view": [ + { + "mark": [ + { + "type": "point", + "encoding": [ + {"channel": "x", "field": "temperature"}, + {"channel": "y", "field": "wind"}, + {"channel": "color", "field": "condition"}, + ], + } + ], + "scale": [ + {"channel": "x", "type": "linear"}, + {"channel": "y", "type": "linear"}, + {"channel": "color", "type": "categorical"}, + ], + } + ] + }, +) + +scatter_with_color_spec_vl = { + "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", + "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, + "encoding": { + "color": { + "field": "condition", + "scale": {"type": "ordinal"}, + "type": "nominal", + }, + "x": { + "field": "temperature", + "scale": {"type": "linear"}, + "type": "quantitative", + }, + "y": {"field": "wind", "scale": {"type": "linear"}, "type": "quantitative"}, + }, + "mark": "point", +} + +bubble_spec_d = build_spec( + data(["temperature", "wind", "precipitation"]), + { + "view": [ + { + "mark": [ + { + "type": "point", + "encoding": [ + {"channel": "x", "field": "temperature"}, + {"channel": "y", "field": "wind"}, + {"channel": "size", "field": "precipitation"}, + ], + } + ], + "scale": [ + {"channel": "x", "type": "linear"}, + {"channel": "y", "type": "linear"}, + {"channel": "size", "type": "linear"}, + ], + } + ] + }, +) + +bubble_spec_vl = { + "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", + "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, + "encoding": { + "size": { + "field": "precipitation", + "scale": {"type": "linear"}, + "type": "quantitative", + }, + "x": { + "field": "temperature", + "scale": {"type": "linear"}, + "type": "quantitative", + }, + "y": {"field": "wind", "scale": {"type": "linear"}, "type": "quantitative"}, + }, + "mark": "point", +} + @pytest.mark.parametrize( "spec, expected_vl", @@ -201,6 +367,10 @@ def build_spec(*args): (tick_log_spec_d, tick_log_spec_vl), (bar_spec_d, bar_spec_vl), (histogram_spec_d, histogram_spec_vl), + (binned_histogram_spec_d, binned_histogram_spec_vl), + (scatter_spec_d, scatter_spec_vl), + (scatter_with_color_spec_d, scatter_with_color_spec_vl), + (bubble_spec_d, bubble_spec_vl), ], ) def test_single_view_single_mark( From d8a708987ad77cc3da361aa3c8fe371c21f7698c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Tue, 15 Nov 2022 11:03:37 +0100 Subject: [PATCH 20/45] test: stacked --- draco/tests/renderer/test_altair_renderer.py | 119 +++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/draco/tests/renderer/test_altair_renderer.py b/draco/tests/renderer/test_altair_renderer.py index e782a7c8..99615deb 100644 --- a/draco/tests/renderer/test_altair_renderer.py +++ b/draco/tests/renderer/test_altair_renderer.py @@ -379,3 +379,122 @@ def test_single_view_single_mark( chart = renderer.render(spec, df) vl = chart.to_dict() assert vl_specs_equal(vl, expected_vl) + + +stacked_bar_spec_d = build_spec( + data(["temperature", "condition"]), + { + "view": [ + { + "mark": [ + { + "type": "bar", + "encoding": [ + {"channel": "x", "field": "temperature", "binning": 10}, + {"channel": "y", "aggregate": "count", "stack": "zero"}, + {"channel": "color", "field": "condition"}, + ], + } + ], + "scale": [ + { + "channel": "x", + "type": "linear", + }, + {"channel": "y", "type": "linear", "zero": "true"}, + {"channel": "color", "type": "categorical"}, + ], + } + ] + }, +) + +stacked_bar_spec_vl = { + "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", + "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, + "encoding": { + "color": { + "field": "condition", + "type": "nominal", + "scale": {"type": "ordinal"}, + }, + "x": { + "bin": {"maxbins": 10}, + "field": "temperature", + "scale": {"type": "linear"}, + "type": "quantitative", + }, + "y": { + "aggregate": "count", + "scale": {"type": "linear", "zero": True}, + "stack": "zero", + }, + }, + "mark": "bar", +} + +normalized_stacked_bar_spec_d = build_spec( + data(["temperature", "condition"]), + { + "view": [ + { + "mark": [ + { + "type": "bar", + "encoding": [ + { + "channel": "x", + "aggregate": "count", + "stack": "normalize", + }, + {"channel": "y", "field": "temperature", "binning": 10}, + {"channel": "color", "field": "condition"}, + ], + } + ], + "scale": [ + {"channel": "x", "type": "linear", "zero": "true"}, + {"channel": "y", "type": "linear"}, + {"channel": "color", "type": "categorical"}, + ], + } + ] + }, +) + +normalized_stacked_bar_spec_vl = { + "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", + "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, + "encoding": { + "color": { + "field": "condition", + "type": "nominal", + "scale": {"type": "ordinal"}, + }, + "x": { + "aggregate": "count", + "scale": {"type": "linear", "zero": True}, + "stack": "normalize", + }, + "y": { + "bin": {"maxbins": 10}, + "field": "temperature", + "scale": {"type": "linear"}, + "type": "quantitative", + }, + }, + "mark": "bar", +} + + +@pytest.mark.parametrize( + "spec, expected_vl", + [ + (stacked_bar_spec_d, stacked_bar_spec_vl), + (normalized_stacked_bar_spec_d, normalized_stacked_bar_spec_vl), + ], +) +def test_stacked(spec: SpecificationDict, expected_vl: dict, renderer: AltairRenderer): + chart = renderer.render(spec, df) + vl = chart.to_dict() + assert vl_specs_equal(vl, expected_vl) From e098422ff354c7f71456f3a0534c781a3e0fcb0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Tue, 15 Nov 2022 13:11:20 +0100 Subject: [PATCH 21/45] fix: handle layering properly --- draco/renderer/altair_renderer.py | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/draco/renderer/altair_renderer.py b/draco/renderer/altair_renderer.py index e757c198..d0ed0491 100644 --- a/draco/renderer/altair_renderer.py +++ b/draco/renderer/altair_renderer.py @@ -21,7 +21,12 @@ Used to abstract away the final type of the produced visualization object. """ VegaLiteChart = TypeVar( - "VegaLiteChart", alt.VConcatChart, alt.HConcatChart, alt.FacetChart, alt.Chart + "VegaLiteChart", + alt.VConcatChart, + alt.HConcatChart, + alt.FacetChart, + alt.Chart, + alt.LayerChart, ) @@ -44,6 +49,7 @@ class ViewContext(RootContext): the dictionary-based specification at the `View` level. """ + layers: list[VegaLiteChart] view: View @@ -80,10 +86,16 @@ def render(self, spec: SpecificationDict, data: DataFrame) -> VegaLiteChart: # Traverse the specification dict and invoke the appropriate visitor for v in spec.view: + layers: list[VegaLiteChart] = [] for m in v.mark: chart = self.__visit_mark( ctx=MarkContext( - spec=spec, chart=chart, chart_views=chart_views, view=v, mark=m + spec=spec, + chart=chart, + chart_views=chart_views, + layers=layers, + view=v, + mark=m, ) ) for e in m.encoding: @@ -92,13 +104,21 @@ def render(self, spec: SpecificationDict, data: DataFrame) -> VegaLiteChart: spec=spec, chart=chart, chart_views=chart_views, + layers=layers, view=v, mark=m, encoding=e, ) ) + layers.append(chart) chart = self.__visit_view( - ctx=ViewContext(spec=spec, chart=chart, chart_views=chart_views, view=v) + ctx=ViewContext( + spec=spec, + chart=chart, + chart_views=chart_views, + layers=layers, + view=v, + ) ) chart_views.append(chart) return self.__visit_root( @@ -130,7 +150,7 @@ def __visit_view(self, ctx: ViewContext) -> VegaLiteChart: :return: The chart with the view applied. :raises ValueError: if the facet channel is not supported """ - view, chart = (ctx.view, ctx.chart) + view, chart, layers = (ctx.view, ctx.chart, ctx.layers) if view.facet is not None: for f in view.facet: channel = f.channel @@ -147,7 +167,8 @@ def __visit_view(self, ctx: ViewContext) -> VegaLiteChart: chart = chart.facet(column=alt.Column(**facet_args)) case _: raise ValueError(f"Unknown facet channel: {channel}") - return chart + return chart + return alt.layer(*layers) if len(layers) > 1 else layers[0] def __visit_mark(self, ctx: MarkContext) -> VegaLiteChart: """ From 53d47cef791448a66516af2f43ca912093c99255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Tue, 15 Nov 2022 13:11:45 +0100 Subject: [PATCH 22/45] test: Multi Mark (Layered) --- draco/tests/renderer/test_altair_renderer.py | 70 ++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/draco/tests/renderer/test_altair_renderer.py b/draco/tests/renderer/test_altair_renderer.py index 99615deb..98bebc1f 100644 --- a/draco/tests/renderer/test_altair_renderer.py +++ b/draco/tests/renderer/test_altair_renderer.py @@ -498,3 +498,73 @@ def test_stacked(spec: SpecificationDict, expected_vl: dict, renderer: AltairRen chart = renderer.render(spec, df) vl = chart.to_dict() assert vl_specs_equal(vl, expected_vl) + + +bar_with_tick_spec_d = build_spec( + data(["temperature"]), + { + "view": [ + { + "mark": [ + { + "type": "bar", + "encoding": [ + { + "channel": "x", + "aggregate": "mean", + "field": "temperature", + } + ], + }, + { + "type": "tick", + "encoding": [{"channel": "x", "field": "temperature"}], + }, + ], + "scale": [{"channel": "x", "type": "linear", "zero": "true"}], + } + ] + }, +) + +bar_with_tick_spec_vl = { + "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", + "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, + "layer": [ + { + "encoding": { + "x": { + "aggregate": "mean", + "field": "temperature", + "scale": {"type": "linear", "zero": True}, + "type": "quantitative", + } + }, + "mark": "bar", + }, + { + "encoding": { + "x": { + "field": "temperature", + "scale": {"type": "linear", "zero": True}, + "type": "quantitative", + } + }, + "mark": "tick", + }, + ], +} + + +@pytest.mark.parametrize( + "spec, expected_vl", + [ + (bar_with_tick_spec_d, bar_with_tick_spec_vl), + ], +) +def test_multi_mark( + spec: SpecificationDict, expected_vl: dict, renderer: AltairRenderer +): + chart = renderer.render(spec, df) + vl = chart.to_dict() + assert vl_specs_equal(vl, expected_vl) From 88ef8ef00ca37e5af00ac6bf16e1a62e2c825c45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Tue, 15 Nov 2022 13:24:12 +0100 Subject: [PATCH 23/45] fix: type checker error thrown by unbounded generic --- draco/renderer/altair_renderer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/draco/renderer/altair_renderer.py b/draco/renderer/altair_renderer.py index d0ed0491..d92f6ea6 100644 --- a/draco/renderer/altair_renderer.py +++ b/draco/renderer/altair_renderer.py @@ -43,7 +43,7 @@ class RootContext(Generic[VegaLiteChart]): @dataclass(frozen=True) -class ViewContext(RootContext): +class ViewContext(RootContext[VegaLiteChart]): """ Visitor callback context available when processing the dictionary-based specification at the `View` level. From 7727e2547c412e3bcf18b3f6f1ee5507c9cd8ad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Tue, 15 Nov 2022 13:24:20 +0100 Subject: [PATCH 24/45] test: facets --- draco/tests/renderer/test_altair_renderer.py | 106 +++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/draco/tests/renderer/test_altair_renderer.py b/draco/tests/renderer/test_altair_renderer.py index 98bebc1f..101c0072 100644 --- a/draco/tests/renderer/test_altair_renderer.py +++ b/draco/tests/renderer/test_altair_renderer.py @@ -568,3 +568,109 @@ def test_multi_mark( chart = renderer.render(spec, df) vl = chart.to_dict() assert vl_specs_equal(vl, expected_vl) + + +scatterplot_columns_spec_d = build_spec( + data(["temperature", "wind", "condition"]), + { + "view": [ + { + "mark": [ + { + "type": "point", + "encoding": [ + {"channel": "x", "field": "temperature"}, + {"channel": "y", "field": "wind"}, + ], + } + ], + "scale": [ + {"channel": "x", "type": "linear"}, + {"channel": "y", "type": "linear"}, + ], + "facet": [ + {"channel": "col", "field": "condition"}, + ], + } + ] + }, +) + +scatterplot_columns_spec_vl = { + "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", + "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, + "facet": {"column": {"field": "condition", "type": "nominal"}}, + "spec": { + "encoding": { + "x": { + "field": "temperature", + "scale": {"type": "linear"}, + "type": "quantitative", + }, + "y": {"field": "wind", "scale": {"type": "linear"}, "type": "quantitative"}, + }, + "mark": "point", + }, +} + +scatterplot_columns_binned_spec_d = build_spec( + data(["temperature", "wind", "condition"]), + { + "view": [ + { + "mark": [ + { + "type": "point", + "encoding": [ + {"channel": "x", "field": "condition"}, + {"channel": "y", "field": "wind"}, + ], + } + ], + "scale": [ + {"channel": "x", "type": "ordinal"}, + {"channel": "y", "type": "linear"}, + ], + "facet": [ + {"channel": "col", "field": "temperature", "binning": 10}, + ], + } + ] + }, +) + +scatterplot_columns_binned_spec_vl = { + "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", + "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, + "facet": { + "column": { + "bin": {"maxbins": 10}, + "field": "temperature", + "type": "quantitative", + } + }, + "spec": { + "encoding": { + "x": { + "field": "condition", + "scale": {"type": "ordinal"}, + "type": "nominal", + }, + "y": {"field": "wind", "scale": {"type": "linear"}, "type": "quantitative"}, + }, + "mark": "point", + }, +} + + +@pytest.mark.parametrize( + "spec, expected_vl", + [ + (scatterplot_columns_spec_d, scatterplot_columns_spec_vl), + (scatterplot_columns_binned_spec_d, scatterplot_columns_binned_spec_vl), + ], +) +def test_facets(spec: SpecificationDict, expected_vl: dict, renderer: AltairRenderer): + chart = renderer.render(spec, df) + vl = chart.to_dict() + assert vl_specs_equal(vl, expected_vl) From e59d9a84b4ff0a72df3a30b24c28027ddd051b12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Tue, 15 Nov 2022 13:36:50 +0100 Subject: [PATCH 25/45] test: multi view --- draco/tests/renderer/test_altair_renderer.py | 140 +++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/draco/tests/renderer/test_altair_renderer.py b/draco/tests/renderer/test_altair_renderer.py index 101c0072..a47f597e 100644 --- a/draco/tests/renderer/test_altair_renderer.py +++ b/draco/tests/renderer/test_altair_renderer.py @@ -674,3 +674,143 @@ def test_facets(spec: SpecificationDict, expected_vl: dict, renderer: AltairRend chart = renderer.render(spec, df) vl = chart.to_dict() assert vl_specs_equal(vl, expected_vl) + + +tick_plot_and_histogram_spec_d = build_spec( + data(["temperature", "condition"]), + { + "view": [ + { + "mark": [ + { + "type": "tick", + "encoding": [{"channel": "y", "field": "temperature"}], + } + ], + "scale": [{"channel": "y", "type": "linear", "zero": "true"}], + }, + { + "mark": [ + { + "type": "bar", + "encoding": [ + {"channel": "x", "field": "condition"}, + {"channel": "y", "aggregate": "count"}, + ], + } + ], + "scale": [ + {"channel": "x", "type": "ordinal"}, + {"channel": "y", "type": "linear", "zero": "true"}, + ], + }, + ] + }, +) +tick_plot_and_histogram_spec_vl = { + "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", + "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, + # TODO adjust `hconcat` / `vconcat` after handling it properly in the renderer + "vconcat": [ + { + "encoding": { + "y": { + "field": "temperature", + "scale": {"type": "linear", "zero": True}, + "type": "quantitative", + } + }, + "mark": "tick", + }, + { + "encoding": { + "x": { + "field": "condition", + "scale": {"type": "ordinal"}, + "type": "nominal", + }, + "y": {"aggregate": "count", "scale": {"type": "linear", "zero": True}}, + }, + "mark": "bar", + }, + ], +} + +tick_plot_and_histogram_shared_scale_spec_d = build_spec( + data(["temperature", "condition"]), + { + "view": [ + { + "mark": [ + { + "type": "tick", + "encoding": [{"channel": "y", "field": "temperature"}], + } + ], + }, + { + "mark": [ + { + "type": "bar", + "encoding": [ + { + "channel": "y", + "field": "temperature", + "aggregate": "mean", + }, + {"channel": "x", "field": "condition"}, + ], + } + ], + "scale": [{"channel": "x", "type": "ordinal"}], + }, + ], + "scale": [{"channel": "y", "type": "linear", "zero": "true"}], + }, +) + +tick_plot_and_histogram_shared_scale_spec_vl = { + "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", + "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, + # TODO adjust `hconcat` / `vconcat` after handling it properly in the renderer + "vconcat": [ + { + "encoding": {"y": {"field": "temperature", "type": "quantitative"}}, + "mark": "tick", + }, + { + "encoding": { + "x": { + "field": "condition", + "type": "nominal", + "scale": {"type": "ordinal"}, + }, + "y": { + "aggregate": "mean", + "field": "temperature", + "type": "quantitative", + }, + }, + "mark": "bar", + }, + ], + "resolve": {"scale": {"y": "shared"}}, +} + + +@pytest.mark.parametrize( + "spec, expected_vl", + [ + (tick_plot_and_histogram_spec_d, tick_plot_and_histogram_spec_vl), + ( + tick_plot_and_histogram_shared_scale_spec_d, + tick_plot_and_histogram_shared_scale_spec_vl, + ), + ], +) +def test_multiple_views( + spec: SpecificationDict, expected_vl: dict, renderer: AltairRenderer +): + chart = renderer.render(spec, df) + vl = chart.to_dict() + assert vl_specs_equal(vl, expected_vl) From ebe3d78d6a889352a02cc6e84a5409f56ad2af0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Tue, 15 Nov 2022 13:54:31 +0100 Subject: [PATCH 26/45] chore: do not cover unreachable code --- draco/renderer/altair_renderer.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/draco/renderer/altair_renderer.py b/draco/renderer/altair_renderer.py index d92f6ea6..c6be896c 100644 --- a/draco/renderer/altair_renderer.py +++ b/draco/renderer/altair_renderer.py @@ -165,8 +165,11 @@ def __visit_view(self, ctx: ViewContext) -> VegaLiteChart: chart = chart.facet(row=alt.Row(**facet_args)) case "col": chart = chart.facet(column=alt.Column(**facet_args)) - case _: - raise ValueError(f"Unknown facet channel: {channel}") + # Should never happen, a pydantic error would be raised sooner + case _: # pragma: no cover + raise ValueError( + f"Unknown facet channel: {channel}" + ) # pragma: no cover return chart return alt.layer(*layers) if len(layers) > 1 else layers[0] @@ -195,8 +198,9 @@ def __visit_mark(self, ctx: MarkContext) -> VegaLiteChart: return chart.mark_tick() case "rect": return chart.mark_rect() - case _: - raise ValueError(f"Unknown mark type: {mark_type}") + # Should never happen, a pydantic error would be raised sooner + case _: # pragma: no cover + raise ValueError(f"Unknown mark type: {mark_type}") # pragma: no cover def __visit_encoding(self, ctx: EncodingContext) -> VegaLiteChart: """ @@ -239,8 +243,11 @@ def __visit_encoding(self, ctx: EncodingContext) -> VegaLiteChart: return chart.encode(shape=alt.Shape(**encoding_args)) case "text": return chart.encode(text=alt.Text(**encoding_args)) - case _: - raise ValueError(f"Unknown channel: {encoding.channel}") + # Should never happen, a pydantic error would be raised sooner + case _: # pragma: no cover + raise ValueError( + f"Unknown channel: {encoding.channel}" + ) # pragma: no cover def __get_field_type(self, fields: list[Field], field_name: FieldName) -> str: """ From ea26fe76683be817dc3037da5ce6e013864aee51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Tue, 15 Nov 2022 13:54:54 +0100 Subject: [PATCH 27/45] test: unknown field in spec raises --- draco/tests/renderer/test_altair_renderer.py | 21 ++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/draco/tests/renderer/test_altair_renderer.py b/draco/tests/renderer/test_altair_renderer.py index a47f597e..c68b3cea 100644 --- a/draco/tests/renderer/test_altair_renderer.py +++ b/draco/tests/renderer/test_altair_renderer.py @@ -814,3 +814,24 @@ def test_multiple_views( chart = renderer.render(spec, df) vl = chart.to_dict() assert vl_specs_equal(vl, expected_vl) + + +def test_unknown_field_raises_value_error(renderer: AltairRenderer): + spec = build_spec( + data(["temperature"]), + { + "view": [ + { + "mark": [ + { + "type": "tick", + "encoding": [{"channel": "x", "field": "not-temperature"}], + } + ], + "scale": [{"channel": "x", "type": "linear"}], + } + ] + }, + ) + with pytest.raises(ValueError): + renderer.render(spec, df) From cc802f6a6bf7872713ecb101f137fc154ab5b8ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Tue, 15 Nov 2022 20:45:46 +0100 Subject: [PATCH 28/45] test: cover all marks and encodings --- draco/tests/renderer/test_altair_renderer.py | 107 +++++++++++++++++-- 1 file changed, 96 insertions(+), 11 deletions(-) diff --git a/draco/tests/renderer/test_altair_renderer.py b/draco/tests/renderer/test_altair_renderer.py index c68b3cea..574235b2 100644 --- a/draco/tests/renderer/test_altair_renderer.py +++ b/draco/tests/renderer/test_altair_renderer.py @@ -5,7 +5,7 @@ from deepdiff import DeepDiff from draco.renderer import AltairRenderer -from draco.types import SpecificationDict +from draco.types import MarkType, SpecificationDict NUM_ROWS = 100 df = pd.DataFrame( @@ -59,6 +59,44 @@ def build_spec(*args): return SpecificationDict.parse_obj(dct) +def specs_with_mark(mark: MarkType): + spec_d = build_spec( + data(["temperature", "wind", "condition"]), + { + "view": [ + { + "mark": [ + { + "type": mark, + "encoding": [ + {"channel": "x", "field": "temperature"}, + {"channel": "shape", "field": "condition"}, + {"channel": "text", "field": "wind"}, + ], + } + ], + "scale": [{"channel": "x", "type": "linear"}], + } + ] + }, + ) + spec_vl = { + "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", + "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, + "encoding": { + "x": { + "field": "temperature", + "scale": {"type": "linear"}, + "type": "quantitative", + }, + "shape": {"field": "condition", "type": "nominal"}, + "text": {"field": "wind", "type": "quantitative"}, + }, + "mark": mark, + } + return spec_d, spec_vl + + # https://dig.cmu.edu/draco2/facts/examples.html#tick-plot tick_spec_d = build_spec( data(["temperature"]), @@ -158,6 +196,7 @@ def build_spec(*args): "mark": "bar", } +# https://dig.cmu.edu/draco2/facts/examples.html#histogram histogram_spec_d = build_spec( data(["condition"]), { @@ -193,6 +232,7 @@ def build_spec(*args): "mark": "bar", } +# https://dig.cmu.edu/draco2/facts/examples.html#binned-histogram binned_histogram_spec_d = build_spec( data(["temperature"]), { @@ -218,7 +258,6 @@ def build_spec(*args): ] }, ) - binned_histogram_spec_vl = { "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, @@ -234,6 +273,7 @@ def build_spec(*args): "mark": "bar", } +# https://dig.cmu.edu/draco2/facts/examples.html#scatterplot scatter_spec_d = build_spec( data(["temperature", "wind"]), { @@ -256,7 +296,6 @@ def build_spec(*args): ] }, ) - scatter_spec_vl = { "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, @@ -271,6 +310,7 @@ def build_spec(*args): "mark": "point", } +# https://dig.cmu.edu/draco2/facts/examples.html#scatterplot-with-color scatter_with_color_spec_d = build_spec( data(["temperature", "wind", "condition"]), { @@ -295,7 +335,6 @@ def build_spec(*args): ] }, ) - scatter_with_color_spec_vl = { "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, @@ -315,6 +354,7 @@ def build_spec(*args): "mark": "point", } +# https://dig.cmu.edu/draco2/facts/examples.html#bubble-chart bubble_spec_d = build_spec( data(["temperature", "wind", "precipitation"]), { @@ -339,7 +379,6 @@ def build_spec(*args): ] }, ) - bubble_spec_vl = { "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, @@ -371,6 +410,8 @@ def build_spec(*args): (scatter_spec_d, scatter_spec_vl), (scatter_with_color_spec_d, scatter_with_color_spec_vl), (bubble_spec_d, bubble_spec_vl), + # Dummy specs for coverage + *list(map(specs_with_mark, ["line", "area", "text", "tick", "rect"])), ], ) def test_single_view_single_mark( @@ -381,6 +422,7 @@ def test_single_view_single_mark( assert vl_specs_equal(vl, expected_vl) +# https://dig.cmu.edu/draco2/facts/examples.html#stacked-bar-chart stacked_bar_spec_d = build_spec( data(["temperature", "condition"]), { @@ -408,7 +450,6 @@ def test_single_view_single_mark( ] }, ) - stacked_bar_spec_vl = { "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, @@ -433,6 +474,7 @@ def test_single_view_single_mark( "mark": "bar", } +# https://dig.cmu.edu/draco2/facts/examples.html#normalized-percentage-stacked-bar-chart normalized_stacked_bar_spec_d = build_spec( data(["temperature", "condition"]), { @@ -461,7 +503,6 @@ def test_single_view_single_mark( ] }, ) - normalized_stacked_bar_spec_vl = { "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, @@ -500,6 +541,7 @@ def test_stacked(spec: SpecificationDict, expected_vl: dict, renderer: AltairRen assert vl_specs_equal(vl, expected_vl) +# https://dig.cmu.edu/draco2/facts/examples.html#bar-with-a-tick bar_with_tick_spec_d = build_spec( data(["temperature"]), { @@ -526,7 +568,6 @@ def test_stacked(spec: SpecificationDict, expected_vl: dict, renderer: AltairRen ] }, ) - bar_with_tick_spec_vl = { "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, @@ -570,6 +611,7 @@ def test_multi_mark( assert vl_specs_equal(vl, expected_vl) +# https://dig.cmu.edu/draco2/facts/examples.html#facet-scatterplot-into-columns scatterplot_columns_spec_d = build_spec( data(["temperature", "wind", "condition"]), { @@ -595,7 +637,6 @@ def test_multi_mark( ] }, ) - scatterplot_columns_spec_vl = { "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, @@ -613,6 +654,49 @@ def test_multi_mark( }, } +scatterplot_rows_spec_d = build_spec( + data(["temperature", "wind", "condition"]), + { + "view": [ + { + "mark": [ + { + "type": "point", + "encoding": [ + {"channel": "x", "field": "temperature"}, + {"channel": "y", "field": "wind"}, + ], + } + ], + "scale": [ + {"channel": "x", "type": "linear"}, + {"channel": "y", "type": "linear"}, + ], + "facet": [ + {"channel": "row", "field": "condition"}, + ], + } + ] + }, +) +scatterplot_rows_spec_vl = { + "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", + "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, + "facet": {"row": {"field": "condition", "type": "nominal"}}, + "spec": { + "encoding": { + "x": { + "field": "temperature", + "scale": {"type": "linear"}, + "type": "quantitative", + }, + "y": {"field": "wind", "scale": {"type": "linear"}, "type": "quantitative"}, + }, + "mark": "point", + }, +} + +# https://dig.cmu.edu/draco2/facts/examples.html#facet-scatterplot-by-binned-data-into-columns scatterplot_columns_binned_spec_d = build_spec( data(["temperature", "wind", "condition"]), { @@ -638,7 +722,6 @@ def test_multi_mark( ] }, ) - scatterplot_columns_binned_spec_vl = { "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, @@ -667,6 +750,7 @@ def test_multi_mark( "spec, expected_vl", [ (scatterplot_columns_spec_d, scatterplot_columns_spec_vl), + (scatterplot_rows_spec_d, scatterplot_rows_spec_vl), (scatterplot_columns_binned_spec_d, scatterplot_columns_binned_spec_vl), ], ) @@ -676,6 +760,7 @@ def test_facets(spec: SpecificationDict, expected_vl: dict, renderer: AltairRend assert vl_specs_equal(vl, expected_vl) +# https://dig.cmu.edu/draco2/facts/examples.html#tick-plot-and-histogram tick_plot_and_histogram_spec_d = build_spec( data(["temperature", "condition"]), { @@ -736,6 +821,7 @@ def test_facets(spec: SpecificationDict, expected_vl: dict, renderer: AltairRend ], } +# https://dig.cmu.edu/draco2/facts/examples.html#tick-plot-and-histogram-with-shared-y-scale tick_plot_and_histogram_shared_scale_spec_d = build_spec( data(["temperature", "condition"]), { @@ -768,7 +854,6 @@ def test_facets(spec: SpecificationDict, expected_vl: dict, renderer: AltairRend "scale": [{"channel": "y", "type": "linear", "zero": "true"}], }, ) - tick_plot_and_histogram_shared_scale_spec_vl = { "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, From bcaa8fec045c4b052f90d4b63974d2e1ee38a2a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Fri, 18 Nov 2022 16:26:51 +0100 Subject: [PATCH 29/45] feat: validate polar marks in schema --- draco/types.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/draco/types.py b/draco/types.py index a02f1632..c85c9720 100644 --- a/draco/types.py +++ b/draco/types.py @@ -236,6 +236,19 @@ class View(SchemaBase): scale: list[Scale] | None = None facet: list[Facet] | None = None + __SUPPORTED_POLAR_MARKS__ = {"bar"} + + @pydantic_validators.root_validator(pre=True) + def check_polar_mark(cls, values: dict): + if values.get("coordinates", "cartesian") == "polar": + for mark in values.get("mark", []): + if mark.get("type", None) not in cls.__SUPPORTED_POLAR_MARKS__: + raise ValueError( + f"polar coordinates only support " + f"{cls.__SUPPORTED_POLAR_MARKS__} marks" + ) + return values + class Field(SchemaBase): """ From 092505500792231d276ee99252d5c053b8b56bb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Fri, 18 Nov 2022 16:27:21 +0100 Subject: [PATCH 30/45] test: polar mark validator --- draco/tests/test_types.py | 43 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/draco/tests/test_types.py b/draco/tests/test_types.py index e34b1783..a12645f7 100644 --- a/draco/tests/test_types.py +++ b/draco/tests/test_types.py @@ -36,3 +36,46 @@ def test_field_validator(data: dict, is_valid: bool): else: with pytest.raises(ValueError): draco_types.Field(**data) + + +@pytest.mark.parametrize( + "data, is_valid", + [ + *[ + ( + dict( + coordinates="cartesian", + mark=[dict(type=t, encoding=[dict(channel="x", field="temp")])], + ), + True, + ) + for t in ["point", "bar", "line", "area", "text", "tick", "rect"] + ], + *[ + ( + dict( + coordinates="polar", + mark=[dict(type=t, encoding=[dict(channel="x", field="temp")])], + ), + False, + ) + for t in ["point", "line", "area", "text", "tick", "rect"] + ], + *[ + ( + dict( + coordinates="polar", + mark=[dict(type=t, encoding=[dict(channel="x", field="temp")])], + ), + True, + ) + for t in ["bar"] + ], + ], +) +def test_view_validator(data: dict, is_valid: bool): + if is_valid: + draco_types.View(**data) + else: + with pytest.raises(ValueError): + draco_types.View(**data) From 1d972e0267da053216495f845e50254f9abbafb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Fri, 18 Nov 2022 16:56:24 +0100 Subject: [PATCH 31/45] feat: validate polar encodings in schema --- draco/types.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/draco/types.py b/draco/types.py index c85c9720..c30ff3a2 100644 --- a/draco/types.py +++ b/draco/types.py @@ -237,9 +237,10 @@ class View(SchemaBase): facet: list[Facet] | None = None __SUPPORTED_POLAR_MARKS__ = {"bar"} + __SUPPORTED_POLAR_ENCODINGS__ = {"x", "y", "color"} @pydantic_validators.root_validator(pre=True) - def check_polar_mark(cls, values: dict): + def check_polar_mark_and_encoding(cls, values: dict): if values.get("coordinates", "cartesian") == "polar": for mark in values.get("mark", []): if mark.get("type", None) not in cls.__SUPPORTED_POLAR_MARKS__: @@ -247,6 +248,15 @@ def check_polar_mark(cls, values: dict): f"polar coordinates only support " f"{cls.__SUPPORTED_POLAR_MARKS__} marks" ) + for encoding in mark.get("encoding", []): + if ( + encoding.get("channel", None) + not in cls.__SUPPORTED_POLAR_ENCODINGS__ + ): + raise ValueError( + f"polar coordinates only support " + f"{cls.__SUPPORTED_POLAR_ENCODINGS__} encodings" + ) return values From 8910c7a5e76917112fe34702a473429c950d5678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Fri, 18 Nov 2022 16:56:36 +0100 Subject: [PATCH 32/45] test: polar encoding validator --- draco/tests/test_types.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/draco/tests/test_types.py b/draco/tests/test_types.py index a12645f7..d4af2062 100644 --- a/draco/tests/test_types.py +++ b/draco/tests/test_types.py @@ -41,6 +41,7 @@ def test_field_validator(data: dict, is_valid: bool): @pytest.mark.parametrize( "data, is_valid", [ + # Cartesian - valid *[ ( dict( @@ -51,6 +52,7 @@ def test_field_validator(data: dict, is_valid: bool): ) for t in ["point", "bar", "line", "area", "text", "tick", "rect"] ], + # Polar - invalid mark, valid encoding *[ ( dict( @@ -61,6 +63,7 @@ def test_field_validator(data: dict, is_valid: bool): ) for t in ["point", "line", "area", "text", "tick", "rect"] ], + # Polar - valid mark, valid encoding *[ ( dict( @@ -71,6 +74,28 @@ def test_field_validator(data: dict, is_valid: bool): ) for t in ["bar"] ], + # Polar - valid mark, invalid encoding + *[ + ( + dict( + coordinates="polar", + mark=[dict(type="bar", encoding=[dict(channel=c, field="temp")])], + ), + False, + ) + for c in ["size", "shape", "text"] + ], + # Polar - valid mark, valid encoding + *[ + ( + dict( + coordinates="polar", + mark=[dict(type="bar", encoding=[dict(channel=c, field="temp")])], + ), + True, + ) + for c in ["x", "y", "color"] + ], ], ) def test_view_validator(data: dict, is_valid: bool): From 94dc9e9cb896c6aa29acb67fd1344ca7083c034d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Fri, 18 Nov 2022 18:29:43 +0100 Subject: [PATCH 33/45] feat: support rendering polar charts --- draco/renderer/altair_renderer.py | 121 ++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/draco/renderer/altair_renderer.py b/draco/renderer/altair_renderer.py index c6be896c..9a3bbced 100644 --- a/draco/renderer/altair_renderer.py +++ b/draco/renderer/altair_renderer.py @@ -178,6 +178,27 @@ def __visit_mark(self, ctx: MarkContext) -> VegaLiteChart: Handles mark-specific configuration. Responsible for applying the mark type to the chart. + :param ctx: The current visitor context. + :return: The chart with the mark applied. + :raises ValueError: if the coordinate type is not supported + """ + coord = ctx.view.coordinates + match coord: + case "cartesian": + return self.__visit_mark_cartesian(ctx) + case "polar": + return self.__visit_mark_polar(ctx) + # Should never happen, a pydantic error would be raised sooner + case _: # pragma: no cover + raise ValueError( + f"Unknown coordinate type: {coord}" + ) # pragma: no cover + + def __visit_mark_cartesian(self, ctx: MarkContext) -> VegaLiteChart: + """ + Handles mark-specific configuration. + Responsible for applying the mark type to a chart in cartesian coordinates. + :param ctx: The current visitor context. :return: The chart with the mark applied. :raises ValueError: if the mark type is not supported @@ -202,11 +223,55 @@ def __visit_mark(self, ctx: MarkContext) -> VegaLiteChart: case _: # pragma: no cover raise ValueError(f"Unknown mark type: {mark_type}") # pragma: no cover + def __visit_mark_polar(self, ctx: MarkContext) -> VegaLiteChart: + """ + Handles mark-specific configuration. + Responsible for applying the mark type to a chart in polar coordinates. + + :param ctx: The current visitor context. + :return: The chart with the mark applied. + :raises ValueError: if the mark type is not supported + """ + chart, encodings, mark_type = (ctx.chart, ctx.mark.encoding, ctx.mark.type) + match mark_type: + case "bar": + encodes_x_and_y = all([e.channel in ["x", "y"] for e in encodings]) + if encodes_x_and_y: + return chart.mark_arc(stroke="#ffffff") + chart.mark_text( + radiusOffset=15 + ) + else: + return chart.mark_arc() + # Should never happen, a pydantic error would be raised sooner + case _: # pragma: no cover + raise ValueError(f"Unknown mark type: {mark_type}") # pragma: no cover + def __visit_encoding(self, ctx: EncodingContext) -> VegaLiteChart: """ Handles encoding-specific configuration. Responsible for applying the encoding to the chart. + :param ctx: The current visitor context. + :return: The updated chart. + :raises ValueError: If an unknown encoding channel is encountered. + """ + coord = ctx.view.coordinates + match coord: + case "cartesian": + return self.__visit_encoding_cartesian(ctx) + case "polar": + return self.__visit_encoding_polar(ctx) + # Should never happen, a pydantic error would be raised sooner + case _: # pragma: no cover + raise ValueError( + f"Unknown coordinate type: {coord}" + ) # pragma: no cover + + def __visit_encoding_cartesian(self, ctx: EncodingContext) -> VegaLiteChart: + """ + Handles encoding-specific configuration. + Responsible for applying the encoding to a chart in cartesian coordinates. + :param ctx: The current visitor context. :return: The updated chart. :raises ValueError: If an unknown encoding channel is encountered. @@ -249,6 +314,62 @@ def __visit_encoding(self, ctx: EncodingContext) -> VegaLiteChart: f"Unknown channel: {encoding.channel}" ) # pragma: no cover + def __visit_encoding_polar(self, ctx: EncodingContext) -> VegaLiteChart: + """ + Handles encoding-specific configuration. + Responsible for applying the encoding to a chart in polar coordinates. + + :param ctx: The current visitor context. + :return: The updated chart. + :raises ValueError: If an unknown encoding channel is encountered. + """ + spec, chart, view, encoding, encodings = ( + ctx.spec, + ctx.chart, + ctx.view, + ctx.encoding, + ctx.mark.encoding, + ) + encodes_x_and_y = all([e.channel in ["x", "y"] for e in encodings]) + + custom_args = {} + if encoding.field is not None: + custom_args["field"] = encoding.field + custom_args["type"] = self.__get_field_type(spec.field, encoding.field) + + if view.scale is not None: + scale_or_none = self.__get_scale_for_encoding(encoding.channel, view.scale) + if scale_or_none is not None: + custom_args["scale"] = scale_or_none + + encoding_args = ( + encoding.dict( + exclude_none=True, exclude={"channel", "field", "binning", "scale"} + ) + | custom_args + ) + + match encoding.channel: + case "x": + return chart.encode( + theta=alt.Theta(**encoding_args), + text=alt.Text( + field=encoding_args["field"], type=encoding_args["type"] + ), + ) + case "y": + if encodes_x_and_y: + return chart.encode(radius=alt.Radius(**encoding_args)) + else: + return chart.encode(theta=alt.Theta(**encoding_args)) + case "color": + return chart.encode(color=alt.Color(**encoding_args)) + # Should never happen, a pydantic error would be raised sooner + case _: # pragma: no cover + raise ValueError( + f"Unknown channel: {encoding.channel}" + ) # pragma: no cover + def __get_field_type(self, fields: list[Field], field_name: FieldName) -> str: """ Returns the type of the field with the given name. From ea7e7a753d628a59e730413730cc6029afcb46c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Fri, 18 Nov 2022 18:29:50 +0100 Subject: [PATCH 34/45] test: polar charts --- draco/tests/renderer/test_altair_renderer.py | 113 +++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/draco/tests/renderer/test_altair_renderer.py b/draco/tests/renderer/test_altair_renderer.py index 574235b2..d47bc65d 100644 --- a/draco/tests/renderer/test_altair_renderer.py +++ b/draco/tests/renderer/test_altair_renderer.py @@ -920,3 +920,116 @@ def test_unknown_field_raises_value_error(renderer: AltairRenderer): ) with pytest.raises(ValueError): renderer.render(spec, df) + + +# https://dig.cmu.edu/draco2/facts/examples.html#pie-chart +polar_pie_chart_spec_d = build_spec( + data(["condition", "temperature"]), + { + "view": [ + { + "coordinates": "polar", + "mark": [ + { + "type": "bar", + "encoding": [ + { + "channel": "y", + "aggregate": "count", + "stack": "zero", + }, + {"channel": "color", "field": "condition"}, + ], + } + ], + "scale": [ + {"channel": "y", "type": "linear", "zero": "true"}, + {"channel": "color", "type": "categorical"}, + ], + } + ] + }, +) +polar_pie_chart_spec_vl = { + "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", + "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, + "encoding": { + "color": { + "field": "condition", + "scale": {"type": "ordinal"}, + "type": "nominal", + }, + "theta": { + "aggregate": "count", + "scale": {"type": "linear", "zero": True}, + "stack": "zero", + }, + }, + "mark": "arc", +} + +# https://dig.cmu.edu/draco2/facts/examples.html#radial-chart +polar_radial_chart_spec_d = build_spec( + data(["condition", "temperature"]), + { + "view": [ + { + "coordinates": "polar", + "mark": [ + { + "type": "bar", + "encoding": [ + {"channel": "x", "field": "condition"}, + { + "channel": "y", + "field": "temperature", + "aggregate": "mean", + }, + ], + } + ], + "scale": [ + {"channel": "x", "type": "ordinal"}, + {"channel": "y", "type": "linear", "zero": "true"}, + ], + } + ] + }, +) +polar_radial_chart_spec_vl = { + "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", + "config": { + "view": {"continuousHeight": 300, "continuousWidth": 400}, + }, + "encoding": { + "radius": { + "aggregate": "mean", + "field": "temperature", + "type": "quantitative", + "scale": {"type": "linear", "zero": True}, + }, + "text": {"field": "condition", "type": "nominal"}, + "theta": { + "field": "condition", + "type": "nominal", + "scale": {"type": "ordinal"}, + }, + }, + "layer": [ + {"mark": {"type": "arc", "stroke": "#ffffff"}}, + {"mark": {"radiusOffset": 15, "type": "text"}}, + ], +} + + +@pytest.mark.parametrize( + "spec, expected_vl", + [ + (polar_pie_chart_spec_d, polar_pie_chart_spec_vl), + (polar_radial_chart_spec_d, polar_radial_chart_spec_vl), + ], +) +def test_polar(spec: SpecificationDict, expected_vl: dict, renderer: AltairRenderer): + chart = renderer.render(spec, df) + vl = chart.to_dict() + assert vl_specs_equal(vl, expected_vl) From bb7547a7adfa384ad6bf9d71baf66afbb20cd6bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Fri, 18 Nov 2022 18:51:30 +0100 Subject: [PATCH 35/45] feat: handle multi views Support on-demand concats --- draco/renderer/altair_renderer.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/draco/renderer/altair_renderer.py b/draco/renderer/altair_renderer.py index 9a3bbced..3fe1ef4e 100644 --- a/draco/renderer/altair_renderer.py +++ b/draco/renderer/altair_renderer.py @@ -1,5 +1,6 @@ +import logging from dataclasses import dataclass -from typing import Generic, TypeVar +from typing import Generic, Literal, TypeVar import altair as alt from pandas import DataFrame @@ -16,6 +17,8 @@ ) from .base_renderer import BaseRenderer +logger = logging.getLogger(__name__) + """ Generic parameter for the type of the produced visualization object. Used to abstract away the final type of the produced visualization object. @@ -79,6 +82,16 @@ class AltairRenderer(BaseRenderer[VegaLiteChart]): represented as an `Altair `_ chart object. """ + def __init__(self, concat_mode: Literal["hconcat", "vconcat"] | None = None): + """ + Instantiates a new `Altair `-based renderer. + + :param concat_mode: The concatenation mode to use + when concatenating multiple views. + Only the first view is returned if `None`. + """ + self.concat_mode = concat_mode + def render(self, spec: SpecificationDict, data: DataFrame) -> VegaLiteChart: # initial chart to be mutated by the visitor callbacks chart = alt.Chart(data) @@ -134,7 +147,16 @@ def __visit_root(self, ctx: RootContext) -> VegaLiteChart: :return: The chart with the root configuration applied. """ views = ctx.chart_views - chart = len(views) > 1 and alt.vconcat(*views) or views[0] + chart = views[0] + if len(views) > 1 and self.concat_mode is not None: + chart = getattr(alt, self.concat_mode)(*views) + else: + logger.log( + level=logging.WARNING, + msg="No concatenation performed on multiple views. " + "Returning the first view.", + ) + if ctx.spec.scale is not None: channels = [s.channel for s in ctx.spec.scale] resolve_scale_args = {c: "shared" for c in channels} From dfada105e388611c69c65183f624e99ae2b34c28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Fri, 18 Nov 2022 18:51:38 +0100 Subject: [PATCH 36/45] test: multi views --- draco/tests/renderer/test_altair_renderer.py | 87 ++++++++++++++++++-- 1 file changed, 78 insertions(+), 9 deletions(-) diff --git a/draco/tests/renderer/test_altair_renderer.py b/draco/tests/renderer/test_altair_renderer.py index d47bc65d..6be8fc3d 100644 --- a/draco/tests/renderer/test_altair_renderer.py +++ b/draco/tests/renderer/test_altair_renderer.py @@ -1,4 +1,5 @@ import random +from typing import Literal import pandas as pd import pytest @@ -41,6 +42,16 @@ def renderer(): return AltairRenderer() +@pytest.fixture +def renderer_with_vconcat(): + return AltairRenderer(concat_mode="vconcat") + + +@pytest.fixture +def renderer_with_hconcat(): + return AltairRenderer(concat_mode="hconcat") + + def vl_specs_equal(a: dict, b: dict) -> bool: exclude_from_comparison = {"config", "datasets", "data", "$schema"} diff = DeepDiff( @@ -792,11 +803,10 @@ def test_facets(spec: SpecificationDict, expected_vl: dict, renderer: AltairRend ] }, ) -tick_plot_and_histogram_spec_vl = { +tick_plot_and_histogram_spec_base_vl = { "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, - # TODO adjust `hconcat` / `vconcat` after handling it properly in the renderer - "vconcat": [ + "CONCAT_MODE": [ { "encoding": { "y": { @@ -854,11 +864,10 @@ def test_facets(spec: SpecificationDict, expected_vl: dict, renderer: AltairRend "scale": [{"channel": "y", "type": "linear", "zero": "true"}], }, ) -tick_plot_and_histogram_shared_scale_spec_vl = { +tick_plot_and_histogram_shared_scale_spec_base_vl = { "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, - # TODO adjust `hconcat` / `vconcat` after handling it properly in the renderer - "vconcat": [ + "CONCAT_MODE": [ { "encoding": {"y": {"field": "temperature", "type": "quantitative"}}, "mark": "tick", @@ -883,17 +892,31 @@ def test_facets(spec: SpecificationDict, expected_vl: dict, renderer: AltairRend } +def prepare_multi_view( + vl_spec: dict, concat_mode: Literal["vconcat", "hconcat"] | None = None +) -> dict: + result = vl_spec.copy() + if concat_mode is not None: + result[concat_mode] = result.pop("CONCAT_MODE") + else: + result = result | result.pop("CONCAT_MODE")[0] + return result + + @pytest.mark.parametrize( "spec, expected_vl", [ - (tick_plot_and_histogram_spec_d, tick_plot_and_histogram_spec_vl), + ( + tick_plot_and_histogram_spec_d, + prepare_multi_view(tick_plot_and_histogram_spec_base_vl), + ), ( tick_plot_and_histogram_shared_scale_spec_d, - tick_plot_and_histogram_shared_scale_spec_vl, + prepare_multi_view(tick_plot_and_histogram_shared_scale_spec_base_vl), ), ], ) -def test_multiple_views( +def test_multiple_views_no_concat( spec: SpecificationDict, expected_vl: dict, renderer: AltairRenderer ): chart = renderer.render(spec, df) @@ -901,6 +924,52 @@ def test_multiple_views( assert vl_specs_equal(vl, expected_vl) +@pytest.mark.parametrize( + "spec, expected_vl", + [ + ( + tick_plot_and_histogram_spec_d, + prepare_multi_view(tick_plot_and_histogram_spec_base_vl, "hconcat"), + ), + ( + tick_plot_and_histogram_shared_scale_spec_d, + prepare_multi_view( + tick_plot_and_histogram_shared_scale_spec_base_vl, "hconcat" + ), + ), + ], +) +def test_multiple_views_hconcat( + spec: SpecificationDict, expected_vl: dict, renderer_with_hconcat: AltairRenderer +): + chart = renderer_with_hconcat.render(spec, df) + vl = chart.to_dict() + assert vl_specs_equal(vl, expected_vl) + + +@pytest.mark.parametrize( + "spec, expected_vl", + [ + ( + tick_plot_and_histogram_spec_d, + prepare_multi_view(tick_plot_and_histogram_spec_base_vl, "vconcat"), + ), + ( + tick_plot_and_histogram_shared_scale_spec_d, + prepare_multi_view( + tick_plot_and_histogram_shared_scale_spec_base_vl, "vconcat" + ), + ), + ], +) +def test_multiple_views_vconcat( + spec: SpecificationDict, expected_vl: dict, renderer_with_vconcat: AltairRenderer +): + chart = renderer_with_vconcat.render(spec, df) + vl = chart.to_dict() + assert vl_specs_equal(vl, expected_vl) + + def test_unknown_field_raises_value_error(renderer: AltairRenderer): spec = build_spec( data(["temperature"]), From 76795ec909d9cd2937deebefd77ec1e5a6927e10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Wed, 7 Dec 2022 15:11:22 +0100 Subject: [PATCH 37/45] fix: satisfy CodeQL Attempts to fix "Explicit returns mixed with implicit (fall through) returns" --- draco/renderer/altair_renderer.py | 44 +++++++++++++------------------ 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/draco/renderer/altair_renderer.py b/draco/renderer/altair_renderer.py index 3fe1ef4e..e28a787d 100644 --- a/draco/renderer/altair_renderer.py +++ b/draco/renderer/altair_renderer.py @@ -210,11 +210,9 @@ def __visit_mark(self, ctx: MarkContext) -> VegaLiteChart: return self.__visit_mark_cartesian(ctx) case "polar": return self.__visit_mark_polar(ctx) - # Should never happen, a pydantic error would be raised sooner - case _: # pragma: no cover - raise ValueError( - f"Unknown coordinate type: {coord}" - ) # pragma: no cover + + # Should never happen, a pydantic error would be raised sooner + raise ValueError(f"Unknown coordinate type: {coord}") # pragma: no cover def __visit_mark_cartesian(self, ctx: MarkContext) -> VegaLiteChart: """ @@ -241,9 +239,9 @@ def __visit_mark_cartesian(self, ctx: MarkContext) -> VegaLiteChart: return chart.mark_tick() case "rect": return chart.mark_rect() - # Should never happen, a pydantic error would be raised sooner - case _: # pragma: no cover - raise ValueError(f"Unknown mark type: {mark_type}") # pragma: no cover + + # Should never happen, a pydantic error would be raised sooner + raise ValueError(f"Unknown mark type: {mark_type}") # pragma: no cover def __visit_mark_polar(self, ctx: MarkContext) -> VegaLiteChart: """ @@ -264,9 +262,9 @@ def __visit_mark_polar(self, ctx: MarkContext) -> VegaLiteChart: ) else: return chart.mark_arc() - # Should never happen, a pydantic error would be raised sooner - case _: # pragma: no cover - raise ValueError(f"Unknown mark type: {mark_type}") # pragma: no cover + + # Should never happen, a pydantic error would be raised sooner + raise ValueError(f"Unknown mark type: {mark_type}") # pragma: no cover def __visit_encoding(self, ctx: EncodingContext) -> VegaLiteChart: """ @@ -283,11 +281,9 @@ def __visit_encoding(self, ctx: EncodingContext) -> VegaLiteChart: return self.__visit_encoding_cartesian(ctx) case "polar": return self.__visit_encoding_polar(ctx) - # Should never happen, a pydantic error would be raised sooner - case _: # pragma: no cover - raise ValueError( - f"Unknown coordinate type: {coord}" - ) # pragma: no cover + + # Should never happen, a pydantic error would be raised sooner + raise ValueError(f"Unknown coordinate type: {coord}") # pragma: no cover def __visit_encoding_cartesian(self, ctx: EncodingContext) -> VegaLiteChart: """ @@ -330,11 +326,9 @@ def __visit_encoding_cartesian(self, ctx: EncodingContext) -> VegaLiteChart: return chart.encode(shape=alt.Shape(**encoding_args)) case "text": return chart.encode(text=alt.Text(**encoding_args)) - # Should never happen, a pydantic error would be raised sooner - case _: # pragma: no cover - raise ValueError( - f"Unknown channel: {encoding.channel}" - ) # pragma: no cover + + # Should never happen, a pydantic error would be raised sooner + raise ValueError(f"Unknown channel: {encoding.channel}") # pragma: no cover def __visit_encoding_polar(self, ctx: EncodingContext) -> VegaLiteChart: """ @@ -386,11 +380,9 @@ def __visit_encoding_polar(self, ctx: EncodingContext) -> VegaLiteChart: return chart.encode(theta=alt.Theta(**encoding_args)) case "color": return chart.encode(color=alt.Color(**encoding_args)) - # Should never happen, a pydantic error would be raised sooner - case _: # pragma: no cover - raise ValueError( - f"Unknown channel: {encoding.channel}" - ) # pragma: no cover + + # Should never happen, a pydantic error would be raised sooner + raise ValueError(f"Unknown channel: {encoding.channel}") # pragma: no cover def __get_field_type(self, fields: list[Field], field_name: FieldName) -> str: """ From d6f06a8dc8da9a2386c1ae69129c0a6b19753efd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Wed, 7 Dec 2022 17:01:29 +0100 Subject: [PATCH 38/45] refactor: move vega-specific spec to `altair` package --- draco/renderer/__init__.py | 3 +- draco/renderer/altair/__init__.py | 0 .../renderer/{ => altair}/altair_renderer.py | 18 +- draco/renderer/altair/types.py | 310 +++++++++++++++++ draco/renderer/base_renderer.py | 4 +- draco/tests/renderer/altair/__init__.py | 0 .../{ => altair}/test_altair_renderer.py | 22 +- .../tests/{ => renderer/altair}/test_types.py | 2 +- draco/types.py | 314 +----------------- 9 files changed, 335 insertions(+), 338 deletions(-) create mode 100644 draco/renderer/altair/__init__.py rename draco/renderer/{ => altair}/altair_renderer.py (97%) create mode 100644 draco/renderer/altair/types.py create mode 100644 draco/tests/renderer/altair/__init__.py rename draco/tests/renderer/{ => altair}/test_altair_renderer.py (97%) rename draco/tests/{ => renderer/altair}/test_types.py (98%) diff --git a/draco/renderer/__init__.py b/draco/renderer/__init__.py index 1566a9fc..af87af99 100644 --- a/draco/renderer/__init__.py +++ b/draco/renderer/__init__.py @@ -1,4 +1,5 @@ -from .altair_renderer import AltairRenderer +from draco.renderer.altair.altair_renderer import AltairRenderer + from .base_renderer import BaseRenderer __all__ = ["BaseRenderer", "AltairRenderer"] diff --git a/draco/renderer/altair/__init__.py b/draco/renderer/altair/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/draco/renderer/altair_renderer.py b/draco/renderer/altair/altair_renderer.py similarity index 97% rename from draco/renderer/altair_renderer.py rename to draco/renderer/altair/altair_renderer.py index e28a787d..6e11d3dc 100644 --- a/draco/renderer/altair_renderer.py +++ b/draco/renderer/altair/altair_renderer.py @@ -5,7 +5,9 @@ import altair as alt from pandas import DataFrame -from ..types import ( +from draco.renderer.base_renderer import BaseRenderer + +from .types import ( Encoding, EncodingChannel, Field, @@ -15,7 +17,6 @@ SpecificationDict, View, ) -from .base_renderer import BaseRenderer logger = logging.getLogger(__name__) @@ -92,18 +93,19 @@ def __init__(self, concat_mode: Literal["hconcat", "vconcat"] | None = None): """ self.concat_mode = concat_mode - def render(self, spec: SpecificationDict, data: DataFrame) -> VegaLiteChart: + def render(self, spec: dict, data: DataFrame) -> VegaLiteChart: + typed_spec = SpecificationDict.parse_obj(spec) # initial chart to be mutated by the visitor callbacks chart = alt.Chart(data) chart_views: list[VegaLiteChart] = [] # Traverse the specification dict and invoke the appropriate visitor - for v in spec.view: + for v in typed_spec.view: layers: list[VegaLiteChart] = [] for m in v.mark: chart = self.__visit_mark( ctx=MarkContext( - spec=spec, + spec=typed_spec, chart=chart, chart_views=chart_views, layers=layers, @@ -114,7 +116,7 @@ def render(self, spec: SpecificationDict, data: DataFrame) -> VegaLiteChart: for e in m.encoding: chart = self.__visit_encoding( ctx=EncodingContext( - spec=spec, + spec=typed_spec, chart=chart, chart_views=chart_views, layers=layers, @@ -126,7 +128,7 @@ def render(self, spec: SpecificationDict, data: DataFrame) -> VegaLiteChart: layers.append(chart) chart = self.__visit_view( ctx=ViewContext( - spec=spec, + spec=typed_spec, chart=chart, chart_views=chart_views, layers=layers, @@ -135,7 +137,7 @@ def render(self, spec: SpecificationDict, data: DataFrame) -> VegaLiteChart: ) chart_views.append(chart) return self.__visit_root( - ctx=RootContext(spec=spec, chart=chart, chart_views=chart_views) + ctx=RootContext(spec=typed_spec, chart=chart, chart_views=chart_views) ) def __visit_root(self, ctx: RootContext) -> VegaLiteChart: diff --git a/draco/renderer/altair/types.py b/draco/renderer/altair/types.py new file mode 100644 index 00000000..bc7d99ac --- /dev/null +++ b/draco/renderer/altair/types.py @@ -0,0 +1,310 @@ +from typing import Literal + +# granular imports to satisfy `pyright` +import pydantic.class_validators as pydantic_validators +import pydantic.config as pydantic_config +import pydantic.fields as pydantic_fields +import pydantic.main as pydantic_main +import pydantic.types as pydantic_types + +""" +The number of rows in the dataset. +""" +DatasetNumberRows = pydantic_types.PositiveInt + +""" +The name of a data field. +Described as `(field,name)` +""" +FieldName = str + +""" +The type of the data in the column for this field. +One of number, string, boolean, or datetime. +Described as `(field,type)` +""" +FieldType = Literal["number", "string", "boolean", "datetime"] + +""" +The number of unique values. +Described as `(field,unique)` +""" +FieldUnique = pydantic_types.PositiveInt + +""" +The entropy of the field. +Described as `(field,entropy)` +""" +FieldEntropy = pydantic_types.PositiveFloat + +""" +The minimum value. Only used for numbers. +Described as `(field,min)` +""" +FieldMin = float + +""" +The maximum value. Only used for numbers. +Described as `(field,max)` +""" +FieldMax = float + +""" +The standard deviation. Only used for numbers. +Described as `(field,std)` +""" +FieldStd = float + +""" +The frequency of the most common value. Only used for strings. +Described as `(field,freq)` +""" +FieldFreq = pydantic_types.PositiveInt + +""" +When the task regards specific fields, fields can be marked as relevant to the task. +Described as `(field,interesting)` +""" +FieldInteresting = bool + +""" +The coordinates system of the view. Can be one of cartesian, or polar. +Described as `(view,coordinates)`. +""" +ViewCoordinate = Literal["cartesian", "polar"] + +""" +The mark type. One of point, bar, line, area, text, tick, or rect. +Described as `(mark,type)`. +""" +MarkType = Literal["point", "bar", "line", "area", "text", "tick", "rect"] + +""" +The visual channel. One of x, y, color, size, shape, or text. +Same as `ScaleChannel`. +Described as `(encoding,channel)`. +""" +EncodingChannel = Literal["x", "y", "color", "size", "shape", "text"] + +""" +The field that maps to the visual property of the mark. Arbitrary string. +Described as `(encoding,field)`. +""" +EncodingField = FieldName + +""" +How the data is aggregated. One of count, mean, median, min, max, stdev, or sum. +Described as `(encoding,aggregate)`. +""" +EncodingAggregate = Literal["count", "mean", "median", "min", "max", "stdev", "sum"] + +""" +How the data is binned into N bins. Positive integer. +Described as `(encoding,binning)` +""" +EncodingBinning = pydantic_types.PositiveInt + +""" +Stacking strategy. One of zero, center, or normalize. +Described as `(encoding,stack)`. +""" +EncodingStack = Literal["zero", "center", "normalize"] + +""" +The scale channel. One of x, y, color, size, shape, or text. +Same as `EncodingChannel`. +Described as `(scale,channel)`. +""" +ScaleChannel = EncodingChannel + +""" +The scale type. One of linear, log, ordinal, or categorical. +Described as `(scale,type)`. +""" +ScaleType = Literal["linear", "log", "ordinal", "categorical"] + +""" +Whether to include zero in the scale domain. +Described as `(scale,zero)`. +""" +ScaleZero = bool + +""" +The facet channel. Can be one of col and row. +Described as `(facet,channel)`. +""" +FacetChannel = Literal["col", "row"] + +""" +The facet field. Arbitrary string. +Described as `(facet,field)`. +""" +FacetField = FieldName + +""" +Binning a numeric field for faceting. Positive integer. +Described as `(facet,binning)`. +""" +FacetBinning = EncodingBinning + + +class SchemaBase(pydantic_main.BaseModel): + """Base class for all schema classes.""" + + class Config: + # Do not allow fields that are not defined in the schema explicitly. + extra = pydantic_config.Extra.forbid + + +class Encoding(SchemaBase): + """ + Encoding schema. + Encodings define how data fields map to visual properties (channel) of the mark. + + `Read More `_. + """ + + channel: EncodingChannel + field: EncodingField | None = None + aggregate: EncodingAggregate | None = None + binning: EncodingBinning | None = None + stack: EncodingStack | None = None + + @pydantic_validators.root_validator(pre=True) + def check_field_is_present_unless_agg_count(cls, values: dict): + if values.get("aggregate", None) != "count" and "field" not in values: + raise ValueError("field must be present unless aggregate is count") + return values + + +class Mark(SchemaBase): + """ + Mark schema. + A mark represents the graphical mark of the visualization. + + `Read More `_. + """ + + type: MarkType + encoding: list[Encoding] + + +class Scale(SchemaBase): + """ + Scale schema. + Scales map abstract values such as time or temperature to + a visual value such as x- or y-position or color. + + `Read More `_. + """ + + channel: ScaleChannel + type: ScaleType = pydantic_fields.Field(default="linear") + zero: ScaleZero | None = None + + +class Facet(SchemaBase): + """ + Facet schema. + With the facet operator, we can partition a dataset by a field + and create a view for each field. + The resulting chart is often called a small multiples chart. + + `Read More `_. + """ + + channel: FacetChannel + field: FacetField + binning: FacetBinning | None = None + + +class View(SchemaBase): + """ + View schema. + A view can group marks and scales together. + + `Read More `_. + """ + + coordinates: ViewCoordinate = pydantic_fields.Field(default="cartesian") + mark: list[Mark] + scale: list[Scale] | None = None + facet: list[Facet] | None = None + + __SUPPORTED_POLAR_MARKS__ = {"bar"} + __SUPPORTED_POLAR_ENCODINGS__ = {"x", "y", "color"} + + @pydantic_validators.root_validator(pre=True) + def check_polar_mark_and_encoding(cls, values: dict): + if values.get("coordinates", "cartesian") == "polar": + for mark in values.get("mark", []): + if mark.get("type", None) not in cls.__SUPPORTED_POLAR_MARKS__: + raise ValueError( + f"polar coordinates only support " + f"{cls.__SUPPORTED_POLAR_MARKS__} marks" + ) + for encoding in mark.get("encoding", []): + if ( + encoding.get("channel", None) + not in cls.__SUPPORTED_POLAR_ENCODINGS__ + ): + raise ValueError( + f"polar coordinates only support " + f"{cls.__SUPPORTED_POLAR_ENCODINGS__} encodings" + ) + return values + + +class Field(SchemaBase): + """ + Field schema. + Represents a column in the dataset. + Draco can use information about the field type and field statistics. + + `Read More `_. + """ + + name: FieldName + type: FieldType + unique: FieldUnique | None = None + entropy: FieldEntropy | None = None + min: FieldMin | None = None + max: FieldMax | None = None + std: FieldStd | None = None + freq: FieldFreq | None = None + interesting: FieldInteresting | None = None + + __STRING_ONLY_FIELDS__ = {"freq"} + __NUMBER_ONLY_FIELDS__ = {"min", "max", "std"} + + @pydantic_validators.root_validator(pre=True) + def check_no_string_attributes_on_number_type(cls, values: dict): + if values["type"] == "number": + for field in cls.__STRING_ONLY_FIELDS__: + if field in values: + raise ValueError( + f"{field} is not a valid attribute for a number field" + ) + return values + + @pydantic_validators.root_validator(pre=True) + def check_no_number_attributes_on_string_type(cls, values: dict): + if values["type"] == "string": + for field in cls.__NUMBER_ONLY_FIELDS__: + if field in values: + raise ValueError( + f"{field} is not a valid attribute for a string field" + ) + return values + + +class SpecificationDict(SchemaBase): + """ + Specification schema. + Describes a visualization completely. + """ + + number_rows: DatasetNumberRows + field: list[Field] + view: list[View] + scale: list[Scale] | None = None diff --git a/draco/renderer/base_renderer.py b/draco/renderer/base_renderer.py index 58109418..c3565f21 100644 --- a/draco/renderer/base_renderer.py +++ b/draco/renderer/base_renderer.py @@ -3,8 +3,6 @@ from pandas import DataFrame -from ..types import SpecificationDict - T = TypeVar("T") @@ -16,7 +14,7 @@ class BaseRenderer(ABC, Generic[T]): """ @abstractmethod - def render(self, spec: SpecificationDict, data: DataFrame) -> T: + def render(self, spec: dict, data: DataFrame) -> T: """ Render a visualization from a dictionary-based specification and data. diff --git a/draco/tests/renderer/altair/__init__.py b/draco/tests/renderer/altair/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/draco/tests/renderer/test_altair_renderer.py b/draco/tests/renderer/altair/test_altair_renderer.py similarity index 97% rename from draco/tests/renderer/test_altair_renderer.py rename to draco/tests/renderer/altair/test_altair_renderer.py index 6be8fc3d..740ca64c 100644 --- a/draco/tests/renderer/test_altair_renderer.py +++ b/draco/tests/renderer/altair/test_altair_renderer.py @@ -6,7 +6,7 @@ from deepdiff import DeepDiff from draco.renderer import AltairRenderer -from draco.types import MarkType, SpecificationDict +from draco.renderer.altair.types import MarkType NUM_ROWS = 100 df = pd.DataFrame( @@ -67,7 +67,7 @@ def build_spec(*args): dct = {} for arg in args: dct.update(arg) - return SpecificationDict.parse_obj(dct) + return dct def specs_with_mark(mark: MarkType): @@ -426,7 +426,7 @@ def specs_with_mark(mark: MarkType): ], ) def test_single_view_single_mark( - spec: SpecificationDict, expected_vl: dict, renderer: AltairRenderer + spec: dict, expected_vl: dict, renderer: AltairRenderer ): chart = renderer.render(spec, df) vl = chart.to_dict() @@ -546,7 +546,7 @@ def test_single_view_single_mark( (normalized_stacked_bar_spec_d, normalized_stacked_bar_spec_vl), ], ) -def test_stacked(spec: SpecificationDict, expected_vl: dict, renderer: AltairRenderer): +def test_stacked(spec: dict, expected_vl: dict, renderer: AltairRenderer): chart = renderer.render(spec, df) vl = chart.to_dict() assert vl_specs_equal(vl, expected_vl) @@ -614,9 +614,7 @@ def test_stacked(spec: SpecificationDict, expected_vl: dict, renderer: AltairRen (bar_with_tick_spec_d, bar_with_tick_spec_vl), ], ) -def test_multi_mark( - spec: SpecificationDict, expected_vl: dict, renderer: AltairRenderer -): +def test_multi_mark(spec: dict, expected_vl: dict, renderer: AltairRenderer): chart = renderer.render(spec, df) vl = chart.to_dict() assert vl_specs_equal(vl, expected_vl) @@ -765,7 +763,7 @@ def test_multi_mark( (scatterplot_columns_binned_spec_d, scatterplot_columns_binned_spec_vl), ], ) -def test_facets(spec: SpecificationDict, expected_vl: dict, renderer: AltairRenderer): +def test_facets(spec: dict, expected_vl: dict, renderer: AltairRenderer): chart = renderer.render(spec, df) vl = chart.to_dict() assert vl_specs_equal(vl, expected_vl) @@ -917,7 +915,7 @@ def prepare_multi_view( ], ) def test_multiple_views_no_concat( - spec: SpecificationDict, expected_vl: dict, renderer: AltairRenderer + spec: dict, expected_vl: dict, renderer: AltairRenderer ): chart = renderer.render(spec, df) vl = chart.to_dict() @@ -940,7 +938,7 @@ def test_multiple_views_no_concat( ], ) def test_multiple_views_hconcat( - spec: SpecificationDict, expected_vl: dict, renderer_with_hconcat: AltairRenderer + spec: dict, expected_vl: dict, renderer_with_hconcat: AltairRenderer ): chart = renderer_with_hconcat.render(spec, df) vl = chart.to_dict() @@ -963,7 +961,7 @@ def test_multiple_views_hconcat( ], ) def test_multiple_views_vconcat( - spec: SpecificationDict, expected_vl: dict, renderer_with_vconcat: AltairRenderer + spec: dict, expected_vl: dict, renderer_with_vconcat: AltairRenderer ): chart = renderer_with_vconcat.render(spec, df) vl = chart.to_dict() @@ -1098,7 +1096,7 @@ def test_unknown_field_raises_value_error(renderer: AltairRenderer): (polar_radial_chart_spec_d, polar_radial_chart_spec_vl), ], ) -def test_polar(spec: SpecificationDict, expected_vl: dict, renderer: AltairRenderer): +def test_polar(spec: dict, expected_vl: dict, renderer: AltairRenderer): chart = renderer.render(spec, df) vl = chart.to_dict() assert vl_specs_equal(vl, expected_vl) diff --git a/draco/tests/test_types.py b/draco/tests/renderer/altair/test_types.py similarity index 98% rename from draco/tests/test_types.py rename to draco/tests/renderer/altair/test_types.py index d4af2062..57c5874f 100644 --- a/draco/tests/test_types.py +++ b/draco/tests/renderer/altair/test_types.py @@ -1,6 +1,6 @@ import pytest -import draco.types as draco_types +import draco.renderer.altair.types as draco_types @pytest.mark.parametrize( diff --git a/draco/types.py b/draco/types.py index c30ff3a2..fc57be5a 100644 --- a/draco/types.py +++ b/draco/types.py @@ -1,315 +1,3 @@ -from typing import Iterable, Literal, TypeAlias +from typing import Iterable, TypeAlias -# granular imports to satisfy `pyright` -import pydantic.class_validators as pydantic_validators -import pydantic.config as pydantic_config -import pydantic.fields as pydantic_fields -import pydantic.main as pydantic_main -import pydantic.types as pydantic_types - -""" -ASP-based fact representation of a visualization specification. -""" Specification: TypeAlias = Iterable[str] | str - -""" -The number of rows in the dataset. -""" -DatasetNumberRows = pydantic_types.PositiveInt - -""" -The name of a data field. -Described as `(field,name)` -""" -FieldName = str - -""" -The type of the data in the column for this field. -One of number, string, boolean, or datetime. -Described as `(field,type)` -""" -FieldType = Literal["number", "string", "boolean", "datetime"] - -""" -The number of unique values. -Described as `(field,unique)` -""" -FieldUnique = pydantic_types.PositiveInt - -""" -The entropy of the field. -Described as `(field,entropy)` -""" -FieldEntropy = pydantic_types.PositiveFloat - -""" -The minimum value. Only used for numbers. -Described as `(field,min)` -""" -FieldMin = float - -""" -The maximum value. Only used for numbers. -Described as `(field,max)` -""" -FieldMax = float - -""" -The standard deviation. Only used for numbers. -Described as `(field,std)` -""" -FieldStd = float - -""" -The frequency of the most common value. Only used for strings. -Described as `(field,freq)` -""" -FieldFreq = pydantic_types.PositiveInt - -""" -When the task regards specific fields, fields can be marked as relevant to the task. -Described as `(field,interesting)` -""" -FieldInteresting = bool - -""" -The coordinates system of the view. Can be one of cartesian, or polar. -Described as `(view,coordinates)`. -""" -ViewCoordinate = Literal["cartesian", "polar"] - -""" -The mark type. One of point, bar, line, area, text, tick, or rect. -Described as `(mark,type)`. -""" -MarkType = Literal["point", "bar", "line", "area", "text", "tick", "rect"] - -""" -The visual channel. One of x, y, color, size, shape, or text. -Same as `ScaleChannel`. -Described as `(encoding,channel)`. -""" -EncodingChannel = Literal["x", "y", "color", "size", "shape", "text"] - -""" -The field that maps to the visual property of the mark. Arbitrary string. -Described as `(encoding,field)`. -""" -EncodingField = FieldName - -""" -How the data is aggregated. One of count, mean, median, min, max, stdev, or sum. -Described as `(encoding,aggregate)`. -""" -EncodingAggregate = Literal["count", "mean", "median", "min", "max", "stdev", "sum"] - -""" -How the data is binned into N bins. Positive integer. -Described as `(encoding,binning)` -""" -EncodingBinning = pydantic_types.PositiveInt - -""" -Stacking strategy. One of zero, center, or normalize. -Described as `(encoding,stack)`. -""" -EncodingStack = Literal["zero", "center", "normalize"] - -""" -The scale channel. One of x, y, color, size, shape, or text. -Same as `EncodingChannel`. -Described as `(scale,channel)`. -""" -ScaleChannel = EncodingChannel - -""" -The scale type. One of linear, log, ordinal, or categorical. -Described as `(scale,type)`. -""" -ScaleType = Literal["linear", "log", "ordinal", "categorical"] - -""" -Whether to include zero in the scale domain. -Described as `(scale,zero)`. -""" -ScaleZero = bool - -""" -The facet channel. Can be one of col and row. -Described as `(facet,channel)`. -""" -FacetChannel = Literal["col", "row"] - -""" -The facet field. Arbitrary string. -Described as `(facet,field)`. -""" -FacetField = FieldName - -""" -Binning a numeric field for faceting. Positive integer. -Described as `(facet,binning)`. -""" -FacetBinning = EncodingBinning - - -class SchemaBase(pydantic_main.BaseModel): - """Base class for all schema classes.""" - - class Config: - # Do not allow fields that are not defined in the schema explicitly. - extra = pydantic_config.Extra.forbid - - -class Encoding(SchemaBase): - """ - Encoding schema. - Encodings define how data fields map to visual properties (channel) of the mark. - - `Read More `_. - """ - - channel: EncodingChannel - field: EncodingField | None = None - aggregate: EncodingAggregate | None = None - binning: EncodingBinning | None = None - stack: EncodingStack | None = None - - @pydantic_validators.root_validator(pre=True) - def check_field_is_present_unless_agg_count(cls, values: dict): - if values.get("aggregate", None) != "count" and "field" not in values: - raise ValueError("field must be present unless aggregate is count") - return values - - -class Mark(SchemaBase): - """ - Mark schema. - A mark represents the graphical mark of the visualization. - - `Read More `_. - """ - - type: MarkType - encoding: list[Encoding] - - -class Scale(SchemaBase): - """ - Scale schema. - Scales map abstract values such as time or temperature to - a visual value such as x- or y-position or color. - - `Read More `_. - """ - - channel: ScaleChannel - type: ScaleType = pydantic_fields.Field(default="linear") - zero: ScaleZero | None = None - - -class Facet(SchemaBase): - """ - Facet schema. - With the facet operator, we can partition a dataset by a field - and create a view for each field. - The resulting chart is often called a small multiples chart. - - `Read More `_. - """ - - channel: FacetChannel - field: FacetField - binning: FacetBinning | None = None - - -class View(SchemaBase): - """ - View schema. - A view can group marks and scales together. - - `Read More `_. - """ - - coordinates: ViewCoordinate = pydantic_fields.Field(default="cartesian") - mark: list[Mark] - scale: list[Scale] | None = None - facet: list[Facet] | None = None - - __SUPPORTED_POLAR_MARKS__ = {"bar"} - __SUPPORTED_POLAR_ENCODINGS__ = {"x", "y", "color"} - - @pydantic_validators.root_validator(pre=True) - def check_polar_mark_and_encoding(cls, values: dict): - if values.get("coordinates", "cartesian") == "polar": - for mark in values.get("mark", []): - if mark.get("type", None) not in cls.__SUPPORTED_POLAR_MARKS__: - raise ValueError( - f"polar coordinates only support " - f"{cls.__SUPPORTED_POLAR_MARKS__} marks" - ) - for encoding in mark.get("encoding", []): - if ( - encoding.get("channel", None) - not in cls.__SUPPORTED_POLAR_ENCODINGS__ - ): - raise ValueError( - f"polar coordinates only support " - f"{cls.__SUPPORTED_POLAR_ENCODINGS__} encodings" - ) - return values - - -class Field(SchemaBase): - """ - Field schema. - Represents a column in the dataset. - Draco can use information about the field type and field statistics. - - `Read More `_. - """ - - name: FieldName - type: FieldType - unique: FieldUnique | None = None - entropy: FieldEntropy | None = None - min: FieldMin | None = None - max: FieldMax | None = None - std: FieldStd | None = None - freq: FieldFreq | None = None - interesting: FieldInteresting | None = None - - __STRING_ONLY_FIELDS__ = {"freq"} - __NUMBER_ONLY_FIELDS__ = {"min", "max", "std"} - - @pydantic_validators.root_validator(pre=True) - def check_no_string_attributes_on_number_type(cls, values: dict): - if values["type"] == "number": - for field in cls.__STRING_ONLY_FIELDS__: - if field in values: - raise ValueError( - f"{field} is not a valid attribute for a number field" - ) - return values - - @pydantic_validators.root_validator(pre=True) - def check_no_number_attributes_on_string_type(cls, values: dict): - if values["type"] == "string": - for field in cls.__NUMBER_ONLY_FIELDS__: - if field in values: - raise ValueError( - f"{field} is not a valid attribute for a string field" - ) - return values - - -class SpecificationDict(SchemaBase): - """ - Specification schema. - Describes a visualization completely. - """ - - number_rows: DatasetNumberRows - field: list[Field] - view: list[View] - scale: list[Scale] | None = None From 8b96f5508d79d32670916e51824d56c70e766edb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Wed, 7 Dec 2022 17:32:20 +0100 Subject: [PATCH 39/45] ci: pin runners to `ubuntu-20.04` Fixes actions/setup-python#162 --- .github/workflows/book.yml | 4 +++- .github/workflows/codeql.yml | 4 +++- .github/workflows/test.yml | 8 ++++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/book.yml b/.github/workflows/book.yml index f7c42465..d8a323b2 100644 --- a/.github/workflows/book.yml +++ b/.github/workflows/book.yml @@ -7,7 +7,9 @@ on: jobs: book: - runs-on: ubuntu-latest + # https://github.com/actions/setup-python/issues/162#issuecomment-1325307787 + # FIXME: temp change to ubuntu-20.04 from ubuntu-latest to fix python can not found error + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 716fed52..b86c8dab 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -11,7 +11,9 @@ on: jobs: analyze: name: Analyze - runs-on: ubuntu-latest + # https://github.com/actions/setup-python/issues/162#issuecomment-1325307787 + # FIXME: temp change to ubuntu-20.04 from ubuntu-latest to fix python can not found error + runs-on: ubuntu-20.04 permissions: actions: read contents: read diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a6bb12a0..a18aecc7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,9 @@ on: jobs: test: - runs-on: ubuntu-latest + # https://github.com/actions/setup-python/issues/162#issuecomment-1325307787 + # FIXME: temp change to ubuntu-20.04 from ubuntu-latest to fix python can not found error + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 @@ -37,7 +39,9 @@ jobs: fail_ci_if_error: true lint: - runs-on: ubuntu-latest + # https://github.com/actions/setup-python/issues/162#issuecomment-1325307787 + # FIXME: temp change to ubuntu-20.04 from ubuntu-latest to fix python can not found error + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 From 320cf546a5ed1395c000d327ec61052c41557128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Wed, 7 Dec 2022 23:24:02 +0100 Subject: [PATCH 40/45] docs: explain the purpose of the stroke in `__visit_mark_polar` --- draco/renderer/altair/altair_renderer.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/draco/renderer/altair/altair_renderer.py b/draco/renderer/altair/altair_renderer.py index 6e11d3dc..6e8e7312 100644 --- a/draco/renderer/altair/altair_renderer.py +++ b/draco/renderer/altair/altair_renderer.py @@ -259,6 +259,9 @@ def __visit_mark_polar(self, ctx: MarkContext) -> VegaLiteChart: case "bar": encodes_x_and_y = all([e.channel in ["x", "y"] for e in encodings]) if encodes_x_and_y: + # We are setting a white stroke here so that the radial + # slices are visually separated from each other. + # See https://github.com/cmudig/draco2/pull/438#discussion_r1042469389 # noqa: E501 return chart.mark_arc(stroke="#ffffff") + chart.mark_text( radiusOffset=15 ) From aac04b968382527d97f670190fc9af6d35e0a89b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Tue, 13 Dec 2022 09:59:47 +0100 Subject: [PATCH 41/45] refactor: declare methods as `static` where applicable --- draco/renderer/altair/altair_renderer.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/draco/renderer/altair/altair_renderer.py b/draco/renderer/altair/altair_renderer.py index 6e8e7312..149c8ef4 100644 --- a/draco/renderer/altair/altair_renderer.py +++ b/draco/renderer/altair/altair_renderer.py @@ -216,7 +216,8 @@ def __visit_mark(self, ctx: MarkContext) -> VegaLiteChart: # Should never happen, a pydantic error would be raised sooner raise ValueError(f"Unknown coordinate type: {coord}") # pragma: no cover - def __visit_mark_cartesian(self, ctx: MarkContext) -> VegaLiteChart: + @staticmethod + def __visit_mark_cartesian(ctx: MarkContext) -> VegaLiteChart: """ Handles mark-specific configuration. Responsible for applying the mark type to a chart in cartesian coordinates. @@ -245,7 +246,8 @@ def __visit_mark_cartesian(self, ctx: MarkContext) -> VegaLiteChart: # Should never happen, a pydantic error would be raised sooner raise ValueError(f"Unknown mark type: {mark_type}") # pragma: no cover - def __visit_mark_polar(self, ctx: MarkContext) -> VegaLiteChart: + @staticmethod + def __visit_mark_polar(ctx: MarkContext) -> VegaLiteChart: """ Handles mark-specific configuration. Responsible for applying the mark type to a chart in polar coordinates. @@ -389,7 +391,8 @@ def __visit_encoding_polar(self, ctx: EncodingContext) -> VegaLiteChart: # Should never happen, a pydantic error would be raised sooner raise ValueError(f"Unknown channel: {encoding.channel}") # pragma: no cover - def __get_field_type(self, fields: list[Field], field_name: FieldName) -> str: + @staticmethod + def __get_field_type(fields: list[Field], field_name: FieldName) -> str: """ Returns the type of the field with the given name. Needed to map from Draco-spec data types to Vega-Lite data types. @@ -410,8 +413,9 @@ def __get_field_type(self, fields: list[Field], field_name: FieldName) -> str: raise ValueError(f"Unknown field: {field_name}") return renames[field_by_name[0].type] + @staticmethod def __get_scale_for_encoding( - self, channel: EncodingChannel, scales: list[Scale] + channel: EncodingChannel, scales: list[Scale] ) -> alt.Scale | None: """ Returns the scale for the given encoding channel, if any. From 39e400a42265e8c778b44a67dadee854c00f90de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Tue, 13 Dec 2022 10:16:00 +0100 Subject: [PATCH 42/45] docs: document scale options of `SpecificationDict` A spec has either top-level- or view-level scales or both. --- draco/renderer/altair/types.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/draco/renderer/altair/types.py b/draco/renderer/altair/types.py index bc7d99ac..9e345b75 100644 --- a/draco/renderer/altair/types.py +++ b/draco/renderer/altair/types.py @@ -228,9 +228,14 @@ class View(SchemaBase): coordinates: ViewCoordinate = pydantic_fields.Field(default="cartesian") mark: list[Mark] - scale: list[Scale] | None = None facet: list[Facet] | None = None + """ + View-specific scales define scales on a per-channel basis in the view. + `None` means that a top-level scale (shared scale) is present. + """ + scale: list[Scale] | None = None + __SUPPORTED_POLAR_MARKS__ = {"bar"} __SUPPORTED_POLAR_ENCODINGS__ = {"x", "y", "color"} @@ -307,4 +312,9 @@ class SpecificationDict(SchemaBase): number_rows: DatasetNumberRows field: list[Field] view: list[View] + + """ + Top-level scales define shared scales across views. + `None` means no shared scales are used. + """ scale: list[Scale] | None = None From 4e380ec630940ec804e83f02e5c8b17602c877b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Tue, 13 Dec 2022 13:42:06 +0100 Subject: [PATCH 43/45] feat: consider scale type in `__get_field_type` Adds support for determining Vega-Lite field type based on a combination of the scale type and the field's raw data type --- draco/renderer/altair/altair_renderer.py | 128 ++++++++++++++++++++--- 1 file changed, 114 insertions(+), 14 deletions(-) diff --git a/draco/renderer/altair/altair_renderer.py b/draco/renderer/altair/altair_renderer.py index 149c8ef4..3d37c6f7 100644 --- a/draco/renderer/altair/altair_renderer.py +++ b/draco/renderer/altair/altair_renderer.py @@ -20,6 +20,7 @@ logger = logging.getLogger(__name__) + """ Generic parameter for the type of the produced visualization object. Used to abstract away the final type of the produced visualization object. @@ -180,7 +181,7 @@ def __visit_view(self, ctx: ViewContext) -> VegaLiteChart: channel = f.channel facet_args = { "field": f.field, - "type": self.__get_field_type(ctx.spec.field, f.field), + "type": self.__get_field_type(ctx.spec, f.field), } if f.binning is not None: facet_args["bin"] = alt.BinParams(maxbins=f.binning) @@ -306,7 +307,7 @@ def __visit_encoding_cartesian(self, ctx: EncodingContext) -> VegaLiteChart: custom_args = {} if encoding.field is not None: custom_args["field"] = encoding.field - custom_args["type"] = self.__get_field_type(spec.field, encoding.field) + custom_args["type"] = self.__get_field_type(spec, encoding.field) if encoding.binning is not None: custom_args["bin"] = alt.BinParams(maxbins=encoding.binning) @@ -358,7 +359,7 @@ def __visit_encoding_polar(self, ctx: EncodingContext) -> VegaLiteChart: custom_args = {} if encoding.field is not None: custom_args["field"] = encoding.field - custom_args["type"] = self.__get_field_type(spec.field, encoding.field) + custom_args["type"] = self.__get_field_type(spec, encoding.field) if view.scale is not None: scale_or_none = self.__get_scale_for_encoding(encoding.channel, view.scale) @@ -392,26 +393,125 @@ def __visit_encoding_polar(self, ctx: EncodingContext) -> VegaLiteChart: raise ValueError(f"Unknown channel: {encoding.channel}") # pragma: no cover @staticmethod - def __get_field_type(fields: list[Field], field_name: FieldName) -> str: + def __get_encoding_channel_of_field( + views: list[View], field_name: FieldName + ) -> EncodingChannel | None: + """ + Returns the mark encoding channel for the field with the given name. + + :param views: All the views in the spec to search for. + :param field_name: The name of the field to search for. + :return: The encoding channel of the field, or `None` if + the field is not found. + """ + for v in views: + for m in v.mark: + for e in m.encoding: + if e.field == field_name: + return e.channel + + return None + + @staticmethod + def __get_scales_of_spec(spec: SpecificationDict) -> list[Scale]: + """ + Returns all the scales in the spec including the top-level + shared scale and the view-specific scales. + + :param spec: The spec to search through for scales. + :return: A list of all the scales in the spec. + """ + scales: list[Scale] = [] + + # Shared scales + for s in spec.scale or []: + scales.append(s) + + # View-specific scales + for v in spec.view: + for s in v.scale or []: + scales.append(s) + + return scales + + @staticmethod + def __get_field_by_name(fields: list[Field], field_name: FieldName) -> Field: + """ + Returns the field with the given name. + + :param fields: The list of fields to search through. + :param field_name: The name of the field to search for. + :return: The field with the given name. + :raises ValueError: If the field is not found. + """ + for f in fields: + if f.name == field_name: + return f + + raise ValueError(f"Field {field_name} not found") + + @staticmethod + def __get_field_type(spec: SpecificationDict, field_name: FieldName) -> str: """ Returns the type of the field with the given name. Needed to map from Draco-spec data types to Vega-Lite data types. + Also takes the scale's type into account which is associated with the field. - :param fields: list of fields in the specification + :param spec: the whole specification :param field_name: name of the field to look up :return: the type of the field - :raises ValueError: if the field is not found """ + cls = AltairRenderer + __DEFAULT_KEY__ = "default" + # Multi-criteria lookup to determine the type of the field + # based on the scale type (if any) AND the raw data type. renames = { - "number": "quantitative", - "string": "nominal", - "boolean": "nominal", - "datetime": "temporal", + "linear": { + "number": "quantitative", + "string": "nominal", + "boolean": "nominal", + "datetime": "temporal", + }, + "log": { + "number": "quantitative", + "string": "nominal", + "boolean": "nominal", + "datetime": "temporal", + }, + "ordinal": { + "number": "quantitative", + "string": "nominal", + "boolean": "nominal", + "datetime": "temporal", + }, + "categorical": { + "number": "nominal", + "string": "nominal", + "boolean": "nominal", + "datetime": "nominal", + }, + __DEFAULT_KEY__: { + "number": "quantitative", + "string": "nominal", + "boolean": "nominal", + "datetime": "temporal", + }, } - field_by_name = [f for f in fields if f.name == field_name] - if len(field_by_name) == 0: - raise ValueError(f"Unknown field: {field_name}") - return renames[field_by_name[0].type] + + field = cls.__get_field_by_name(spec.field, field_name) + # Look for the encoding channel of the field, so we can match it to a scale + channel = cls.__get_encoding_channel_of_field(spec.view, field_name) + # We might have no channel in case of a faceted field + # --> we map based on the raw data type + if channel is None: + return renames[__DEFAULT_KEY__][field.type] + + # Look for the scale associated with `channel` + scale = cls.__get_scale_for_encoding(channel, cls.__get_scales_of_spec(spec)) + # We might have no scale present for the channel + # --> we map based on the raw data type + key = scale.type if scale is not None else __DEFAULT_KEY__ + return renames[key][field.type] @staticmethod def __get_scale_for_encoding( From bd7ca3baac790d5365aeec987674cb96fca9aba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Tue, 13 Dec 2022 23:57:12 +0100 Subject: [PATCH 44/45] refactor: adjust dict in `__get_field_type` --- draco/renderer/altair/altair_renderer.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/draco/renderer/altair/altair_renderer.py b/draco/renderer/altair/altair_renderer.py index 3d37c6f7..484a522f 100644 --- a/draco/renderer/altair/altair_renderer.py +++ b/draco/renderer/altair/altair_renderer.py @@ -468,21 +468,18 @@ def __get_field_type(spec: SpecificationDict, field_name: FieldName) -> str: renames = { "linear": { "number": "quantitative", - "string": "nominal", - "boolean": "nominal", "datetime": "temporal", }, "log": { "number": "quantitative", - "string": "nominal", - "boolean": "nominal", - "datetime": "temporal", + "datetime": "quantitative", }, "ordinal": { - "number": "quantitative", + "number": "ordinal", + # Accounting for colors "string": "nominal", - "boolean": "nominal", - "datetime": "temporal", + "boolean": "ordinal", + "datetime": "ordinal", }, "categorical": { "number": "nominal", From 25659fe767f487ace762728bff39cb9f17e2e243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Ferenc=20Gyarmati?= Date: Wed, 14 Dec 2022 10:36:55 +0100 Subject: [PATCH 45/45] fix: distinguish `__get_scale_for_encoding` and `__get_alt_scale_for_encoding` --- draco/renderer/altair/altair_renderer.py | 41 ++++++++++++++----- .../renderer/altair/test_altair_renderer.py | 14 +++---- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/draco/renderer/altair/altair_renderer.py b/draco/renderer/altair/altair_renderer.py index 484a522f..457b1b69 100644 --- a/draco/renderer/altair/altair_renderer.py +++ b/draco/renderer/altair/altair_renderer.py @@ -312,7 +312,9 @@ def __visit_encoding_cartesian(self, ctx: EncodingContext) -> VegaLiteChart: custom_args["bin"] = alt.BinParams(maxbins=encoding.binning) if view.scale is not None: - scale_or_none = self.__get_scale_for_encoding(encoding.channel, view.scale) + scale_or_none = self.__get_alt_scale_for_encoding( + encoding.channel, view.scale + ) if scale_or_none is not None: custom_args["scale"] = scale_or_none @@ -362,7 +364,9 @@ def __visit_encoding_polar(self, ctx: EncodingContext) -> VegaLiteChart: custom_args["type"] = self.__get_field_type(spec, encoding.field) if view.scale is not None: - scale_or_none = self.__get_scale_for_encoding(encoding.channel, view.scale) + scale_or_none = self.__get_alt_scale_for_encoding( + encoding.channel, view.scale + ) if scale_or_none is not None: custom_args["scale"] = scale_or_none @@ -476,8 +480,7 @@ def __get_field_type(spec: SpecificationDict, field_name: FieldName) -> str: }, "ordinal": { "number": "ordinal", - # Accounting for colors - "string": "nominal", + "string": "ordinal", "boolean": "ordinal", "datetime": "ordinal", }, @@ -513,9 +516,25 @@ def __get_field_type(spec: SpecificationDict, field_name: FieldName) -> str: @staticmethod def __get_scale_for_encoding( channel: EncodingChannel, scales: list[Scale] + ) -> Scale | None: + """ + Returns the `Scale` for the given encoding channel, if any. + + :param channel: the channel for which to look up a scale + :param scales: the list of scales in the view + :return: the scale for the given channel, or None if no scale is found + """ + for scale in scales: + if scale.channel == channel: + return scale + return None + + @staticmethod + def __get_alt_scale_for_encoding( + channel: EncodingChannel, scales: list[Scale] ) -> alt.Scale | None: """ - Returns the scale for the given encoding channel, if any. + Returns an `alt.Scale` for the given encoding channel, if any. :param channel: the channel for which to look up a scale :param scales: the list of scales in the view @@ -524,9 +543,9 @@ def __get_scale_for_encoding( renames = { "categorical": "ordinal", } - for scale in scales: - if scale.channel == channel: - scale_args = scale.dict(exclude_none=True, exclude={"channel"}) - scale_args["type"] = renames.get(scale.type, scale.type) - return alt.Scale(**scale_args) - return None + scale = AltairRenderer.__get_scale_for_encoding(channel, scales) + if scale is None: + return None + scale_args = scale.dict(exclude_none=True, exclude={"channel"}) + scale_args["type"] = renames.get(scale.type, scale.type) + return alt.Scale(**scale_args) diff --git a/draco/tests/renderer/altair/test_altair_renderer.py b/draco/tests/renderer/altair/test_altair_renderer.py index 740ca64c..c21b056d 100644 --- a/draco/tests/renderer/altair/test_altair_renderer.py +++ b/draco/tests/renderer/altair/test_altair_renderer.py @@ -196,7 +196,7 @@ def specs_with_mark(mark: MarkType): "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, "encoding": { - "x": {"field": "condition", "scale": {"type": "ordinal"}, "type": "nominal"}, + "x": {"field": "condition", "scale": {"type": "ordinal"}, "type": "ordinal"}, "y": { "aggregate": "mean", "field": "temperature", @@ -234,7 +234,7 @@ def specs_with_mark(mark: MarkType): "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", "config": {"view": {"continuousHeight": 300, "continuousWidth": 400}}, "encoding": { - "x": {"field": "condition", "scale": {"type": "ordinal"}, "type": "nominal"}, + "x": {"field": "condition", "scale": {"type": "ordinal"}, "type": "ordinal"}, "y": { "aggregate": "count", "scale": {"type": "linear", "zero": True}, @@ -746,7 +746,7 @@ def test_multi_mark(spec: dict, expected_vl: dict, renderer: AltairRenderer): "x": { "field": "condition", "scale": {"type": "ordinal"}, - "type": "nominal", + "type": "ordinal", }, "y": {"field": "wind", "scale": {"type": "linear"}, "type": "quantitative"}, }, @@ -820,7 +820,7 @@ def test_facets(spec: dict, expected_vl: dict, renderer: AltairRenderer): "x": { "field": "condition", "scale": {"type": "ordinal"}, - "type": "nominal", + "type": "ordinal", }, "y": {"aggregate": "count", "scale": {"type": "linear", "zero": True}}, }, @@ -874,7 +874,7 @@ def test_facets(spec: dict, expected_vl: dict, renderer: AltairRenderer): "encoding": { "x": { "field": "condition", - "type": "nominal", + "type": "ordinal", "scale": {"type": "ordinal"}, }, "y": { @@ -1075,10 +1075,10 @@ def test_unknown_field_raises_value_error(renderer: AltairRenderer): "type": "quantitative", "scale": {"type": "linear", "zero": True}, }, - "text": {"field": "condition", "type": "nominal"}, + "text": {"field": "condition", "type": "ordinal"}, "theta": { "field": "condition", - "type": "nominal", + "type": "ordinal", "scale": {"type": "ordinal"}, }, },