Skip to content

Commit c1d5abf

Browse files
committed
Update Documentation
1 parent 38ccc46 commit c1d5abf

File tree

6 files changed

+214
-265
lines changed

6 files changed

+214
-265
lines changed

mplaltair/__init__.py

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22
import matplotlib
33
import altair
44
import matplotlib.pyplot as plt
5-
import numpy as np
65
from ._convert import _convert
7-
from ._data import _normalize_data, _locate_channel_dtype, _locate_channel_data, _locate_channel_field, _convert_to_mpl_date
86
from ._axis import convert_axis
97
from ._marks import _handle_line
108

@@ -27,7 +25,6 @@ def convert(alt_chart):
2725
"""
2826
chart = parse_chart.ChartMetadata(alt_chart)
2927
fig, ax = plt.subplots()
30-
_normalize_data(chart)
3128

3229
if chart.mark in ['point', 'circle', 'square']: # scatter
3330
mapping = _convert(chart)
@@ -39,58 +36,3 @@ def convert(alt_chart):
3936
convert_axis(ax, chart)
4037
fig.tight_layout()
4138
return fig, ax
42-
43-
44-
def _handle_line(chart, ax):
45-
"""Convert encodings, manipulate data if needed, plot on ax.
46-
47-
Parameters
48-
----------
49-
chart : altair.Chart
50-
The Altair chart object
51-
52-
ax
53-
The Matplotlib axes object
54-
55-
Notes
56-
-----
57-
Fill isn't necessary until mpl-altair can handle multiple plot types in one plot.
58-
Size is unsupported by both Matplotlib and Altair.
59-
When both Color and Stroke are provided, color is ignored and stroke is used.
60-
Shape is unsupported in line graphs unless another plot type is plotted at the same time.
61-
"""
62-
groups = []
63-
kwargs = {}
64-
65-
if chart.encoding.get('opacity'):
66-
groups.append('opacity')
67-
if chart.encoding.get('stroke'):
68-
groups.append('stroke')
69-
elif chart.encoding.get('color'):
70-
groups.append('color')
71-
72-
list_fields = lambda c, g: [chart.encoding[i].field for i in g]
73-
try:
74-
for label, subset in chart.data.groupby(list_fields(chart, groups)):
75-
if 'opacity' in groups:
76-
kwargs['alpha'] = opacity_norm(chart, subset[chart.encoding['opacity'].field].iloc[0])
77-
78-
if 'color' not in groups and 'stroke' not in groups:
79-
kwargs['color'] = matplotlib.rcParams['lines.color']
80-
ax.plot(subset[chart.encoding['x'].field], subset[chart.encoding['y'].field], **kwargs)
81-
except ValueError:
82-
ax.plot(chart.encoding['x'].data, chart.encoding['y'].data)
83-
84-
85-
def opacity_norm(chart, val):
86-
arr = chart.encoding['opacity'].data
87-
if chart.encoding['opacity'].type in ['ordinal', 'nominal', 'temporal']:
88-
unique, indices = np.unique(arr, return_inverse=True)
89-
arr = indices
90-
if chart.encoding['opacity'].type == "temporal":
91-
val = unique.tolist().index(_convert_to_mpl_date(val))
92-
else:
93-
val = unique.tolist().index(val)
94-
data_min, data_max = (arr.min(), arr.max())
95-
desired_min, desired_max = (0.15, 1) # Chosen so that the minimum value is visible (aka nonzero)
96-
return ((val - data_min) / (data_max - data_min)) * (desired_max - desired_min) + desired_min

mplaltair/_axis.py

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ def _set_limits(channel, mark, ax):
1010
Parameters
1111
----------
1212
channel : parse_chart.ChannelMetadata
13-
The mapping of the channel data and metadata
14-
scale : dict
15-
The mapping of the scale metadata and the scale data
13+
The channel data and metadata
14+
mark : str
15+
The chart's mark
16+
ax : matplotlib.axes
1617
"""
1718

1819
_axis_kwargs = {
@@ -28,39 +29,40 @@ def _set_limits(channel, mark, ax):
2829
if channel.scale['domain'] == 'unaggregated':
2930
raise NotImplementedError
3031
else:
31-
lims[_axis_kwargs[channel.channel].get('min')] = channel.scale['domain'][0]
32-
lims[_axis_kwargs[channel.channel].get('max')] = channel.scale['domain'][1]
32+
lims[_axis_kwargs[channel.name].get('min')] = channel.scale['domain'][0]
33+
lims[_axis_kwargs[channel.name].get('max')] = channel.scale['domain'][1]
3334
elif 'type' in channel.scale and channel.scale['type'] != 'linear':
3435
lims = _set_scale_type(channel, ax)
3536
else:
3637
# Include zero on the axis (or not).
3738
# In Altair, scale.zero defaults to False unless the data is unbinned quantitative.
38-
if mark == 'line' and channel.channel == 'x': # TODO: fix channel['mark']
39+
if mark == 'line' and channel.name == 'x':
3940
# Contrary to documentation, Altair defaults to scale.zero=False for the x-axis on line graphs.
41+
# Pass to skip.
4042
pass
4143
else:
4244
# Check that a positive minimum is zero if scale.zero is True:
4345
if ('zero' not in channel.scale or channel.scale['zero'] == True) and min(channel.data) > 0:
44-
lims[_axis_kwargs[channel.channel].get('min')] = 0 # quantitative sets min to be 0 by default
46+
lims[_axis_kwargs[channel.name].get('min')] = 0 # quantitative sets min to be 0 by default
4547

4648
# Check that a negative maximum is zero if scale.zero is True:
4749
if ('zero' not in channel.scale or channel.scale['zero'] == True) and max(channel.data) < 0:
48-
lims[_axis_kwargs[channel.channel].get('max')] = 0
50+
lims[_axis_kwargs[channel.name].get('max')] = 0
4951

5052
elif channel.type == 'temporal':
5153
# determine limits
5254
if 'domain' in channel.scale:
5355
domain = _convert_to_mpl_date(channel.scale['domain'])
54-
lims[_axis_kwargs[channel.channel].get('min')] = domain[0]
55-
lims[_axis_kwargs[channel.channel].get('max')] = domain[1]
56+
lims[_axis_kwargs[channel.name].get('min')] = domain[0]
57+
lims[_axis_kwargs[channel.name].get('max')] = domain[1]
5658
elif 'type' in channel.scale and channel.scale['type'] != 'time':
5759
lims = _set_scale_type(channel, channel.scale)
5860

5961
else:
6062
raise NotImplementedError # Ordinal and Nominal go here?
6163

6264
# set the limits
63-
if channel.channel == 'x':
65+
if channel.name == 'x':
6466
ax.set_xlim(**lims)
6567
else:
6668
ax.set_ylim(**lims)
@@ -73,10 +75,9 @@ def _set_scale_type(channel, ax):
7375
7476
Parameters
7577
----------
76-
channel : dict
77-
The mapping of the channel data and metadata
78-
scale : dict
79-
The mapping of the scale metadata and the scale data
78+
channel : parse_chart.ChannelMetadata
79+
The channel data and metadata
80+
ax : matplotlib.axes
8081
8182
Returns
8283
-------
@@ -104,15 +105,15 @@ def _set_scale_type(channel, ax):
104105
When Matplotlib gets a power scale, the following should work:
105106
106107
exponent = 2 # default exponent value for 'pow' scale
107-
if scale['type'] == 'sqrt':
108+
if channel.scale['type'] == 'sqrt':
108109
exponent = 0.5
109-
elif 'exponent' in scale:
110-
exponent = scale['exponent']
110+
elif 'exponent' in channel.scale:
111+
exponent = channel.scale['exponent']
111112
112-
if channel['axis'] == 'x':
113-
channel['ax'].set_xscale('power_scale', exponent=exponent)
113+
if channel.name == 'x':
114+
ax.set_xscale('power_scale', exponent=exponent)
114115
else: # y-axis
115-
channel['ax'].set_yscale('power_scale', exponent=exponent)
116+
ax.set_yscale('power_scale', exponent=exponent)
116117
"""
117118
raise NotImplementedError
118119

@@ -131,20 +132,20 @@ def _set_tick_locator(channel, ax):
131132
Parameters
132133
----------
133134
channel : parse_chart.ChannelMetadata
134-
The mapping of the channel data and metadata
135-
axis : matplotlib.axes
135+
The channel data and metadata
136+
ax : matplotlib.axes
136137
The mapping of the axis metadata and the scale data
137138
"""
138139
current_axis = {'x': ax.xaxis, 'y': ax.yaxis}
139140
if 'values' in channel.axis:
140141
if channel.type == 'temporal':
141-
current_axis[channel.channel].set_major_locator(ticker.FixedLocator(_convert_to_mpl_date(channel.axis.get('values'))))
142+
current_axis[channel.name].set_major_locator(ticker.FixedLocator(_convert_to_mpl_date(channel.axis.get('values'))))
142143
elif channel.type == 'quantitative':
143-
current_axis[channel.channel].set_major_locator(ticker.FixedLocator(channel.axis.get('values')))
144+
current_axis[channel.name].set_major_locator(ticker.FixedLocator(channel.axis.get('values')))
144145
else:
145146
raise NotImplementedError
146147
elif 'tickCount' in channel.axis:
147-
current_axis[channel.channel].set_major_locator(
148+
current_axis[channel.name].set_major_locator(
148149
ticker.MaxNLocator(steps=[2, 5, 10], nbins=channel.axis.get('tickCount')+1, min_n_ticks=channel.axis.get('tickCount'))
149150
)
150151

@@ -156,8 +157,8 @@ def _set_tick_formatter(channel, ax):
156157
Parameters
157158
----------
158159
channel : parse_chart.ChannelMetadata
159-
The mapping of the channel data and metadata
160-
axis : dict
160+
The channel data and metadata
161+
ax : matplotlib.axes
161162
The mapping of the axis metadata and the scale data
162163
163164
Notes
@@ -179,15 +180,15 @@ def _set_tick_formatter(channel, ax):
179180
if not format_str:
180181
format_str = '%b %d, %Y'
181182

182-
current_axis[channel.channel].set_major_formatter(mdates.DateFormatter(format_str)) # May fail silently
183+
current_axis[channel.name].set_major_formatter(mdates.DateFormatter(format_str)) # May fail silently
183184

184185
elif channel.type == 'quantitative':
185186
if format_str:
186-
current_axis[channel.channel].set_major_formatter(ticker.StrMethodFormatter('{x:' + format_str + '}'))
187+
current_axis[channel.name].set_major_formatter(ticker.StrMethodFormatter('{x:' + format_str + '}'))
187188

188189
# Verify that the format string is valid for Matplotlib and exit nicely if not.
189190
try:
190-
current_axis[channel.channel].get_major_formatter().__call__(1)
191+
current_axis[channel.name].get_major_formatter().__call__(1)
191192
except ValueError:
192193
raise ValueError("Matplotlib only supports format strings as used by `str.format()`."
193194
"Some format strings that work in Altair may not work in Matplotlib."
@@ -202,11 +203,11 @@ def _set_label_angle(channel, ax):
202203
Parameters
203204
----------
204205
channel : parse_chart.ChannelMetadata
205-
The mapping of the channel data and metadata
206-
axis : matplotlib.axes
206+
The channel data and metadata
207+
ax : matplotlib.axes
207208
The mapping of the axis metadata and the scale data
208209
"""
209-
if channel.type == 'temporal' and channel.channel == 'x':
210+
if channel.type == 'temporal' and channel.name == 'x':
210211
for label in ax.get_xticklabels():
211212
# Rotate the labels on the x-axis so they don't run into each other.
212213
label.set_rotation(30)
@@ -220,8 +221,8 @@ def convert_axis(ax, chart):
220221
----------
221222
ax
222223
The Matplotlib axis to be modified
223-
chart
224-
The Altair chart
224+
chart : parse_chart.ChartMetadata
225+
The chart data and metadata
225226
"""
226227

227228
for channel in [chart.encoding['x'], chart.encoding['y']]:

mplaltair/_convert.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ def _convert(chart):
9999
100100
Parameters
101101
----------
102-
chart
103-
The Altair chart.
102+
chart : parse_chart.ChartMetadata
103+
Data and metadata for the Altair chart
104104
105105
Returns
106106
-------

0 commit comments

Comments
 (0)