• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

spedas / pyspedas / 23096825121

14 Mar 2026 09:34PM UTC coverage: 10.65% (-79.8%) from 90.486%
23096825121

push

github

jameswilburlewis
Allow uploading of hidden files

5208 of 48900 relevant lines covered (10.65%)

0.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

2.89
/pyspedas/tplot_tools/MPLPlotter/lineplot.py
1
import numpy as np
1✔
2
import pyspedas
1✔
3
import logging
1✔
4

5

6
def lineplot(var_data,
1✔
7
             var_times,
8
             this_axis,
9
             line_opts,
10
             yaxis_options,
11
             plot_extras,
12
             running_trace_count=None,
13
             time_idxs=None,
14
             style=None,
15
             var_metadata=None):
16
    """
17
    Generate a matplotlib line plot from a tplot variable
18

19
    Parameters
20
    ----------
21
        var_data: dict
22
            The data to be plotted (may have multiple traces)
23
        var_times:
24
            Array of datetime objects to use for x axis
25
        this_axis:
26
            The current axis (plot panel) we're working with
27
        line_opts: dict
28
            A dictionary of line options
29
        yaxis_options: dict
30
            A dictionary of y axis options
31
        plot_extras: dict
32
            A dictionary of 'extra' options (colors, etc)
33
        running_trace_count:
34
            If not Null, an integer representing the number of traces already processed in this pseudovariable. Defaults to None.
35
        time_idxs: np.ndarray
36
            If provided, an integer array specifying the subset of time indices to be plotted. Defaults to None.
37
        style:
38
            A matplotlib style to be used in the plot. Defaults to None.
39
        var_metadata: dict
40
            The metadata dictionary associated with this tplot variable (used as a fallback for trace labels). Defaults to None.
41

42
    Returns
43
    -------
44
        True
45

46
    """
47
    alpha = plot_extras.get('alpha')
×
48

49
    if len(var_data.y.shape) == 1:
×
50
        num_lines = 1
×
51
    else:
52
        num_lines = var_data.y.shape[1]
×
53

54
    is_errorbar_plot = False
×
55
    if 'dy' in var_data._fields:
×
56
        is_errorbar_plot = True
×
57

58
    if yaxis_options.get('legend_names') is not None:
×
59
        labels = yaxis_options['legend_names']
×
60
        labels = get_trace_options(labels, running_trace_count, num_lines)
×
61

62
        if labels[0] is None:
×
63
            labels = None
×
64
    else:
65
        labels = None
×
66
        if var_metadata.get('CDF') is not None:
×
67
            labels = var_metadata['CDF'].get('LABELS')
×
68

69
    legend_location = yaxis_options.get('legend_location')
×
70

71
    bbox_to_anchor = None
×
72
    if legend_location is not None:
×
73
        if legend_location == 'spedas':
×
74
            # the spedas legend puts the legend on the outside of the panel
75
            # to the right of the panel (just like in IDL)
76
            legend_location = 'center left'
×
77
            bbox_to_anchor = (1.04, 0.5)
×
78
    else:
79
        legend_location = 'upper right'
×
80

81
    legend_size = yaxis_options.get('legend_size')
×
82
    legend_shadow = yaxis_options.get('legend_shadow')
×
83
    legend_title = yaxis_options.get('legend_title')
×
84
    legend_titlesize = yaxis_options.get('legend_titlesize')
×
85
    legend_color = yaxis_options.get('legend_color')
×
86
    legend_markerfirst = yaxis_options.get('legend_markerfirst')
×
87
    legend_markerscale = yaxis_options.get('legend_markerscale')
×
88
    legend_linewidth = yaxis_options.get('legend_linewidth')
×
89
    legend_edgecolor = yaxis_options.get('legend_edgecolor')
×
90
    legend_facecolor = yaxis_options.get('legend_facecolor')
×
91
    legend_frameon = yaxis_options.get('legend_frameon')
×
92
    legend_ncols = yaxis_options.get('legend_ncols')
×
93
    if legend_ncols is None:
×
94
        legend_ncols = 1
×
95

96
    if legend_linewidth is None:
×
97
        legend_linewidth = 4
×
98

99
    if legend_size is None:
×
100
        legend_size = pyspedas.tplot_tools.tplot_opt_glob.get('charsize')
×
101

102
    markers = None
×
103
    if line_opts.get('marker') is not None:
×
104
        markers = line_opts['marker']
×
105
        markers = get_trace_options(markers, running_trace_count, num_lines, repeat=True)
×
106

107
    colors = None
×
108
    if plot_extras.get('line_color') is not None:
×
109
        colors = plot_extras['line_color']
×
110
    else:
111
        if style is None:
×
112
            if num_lines == 1:
×
113
                colors = ['k']
×
114
            elif num_lines == 2:
×
115
                colors = ['r', 'g']
×
116
            elif num_lines == 3:
×
117
                colors = ['b', 'g', 'r']
×
118
            elif num_lines == 4:
×
119
                colors = ['b', 'g', 'r', 'k']
×
120
            else:
121
                colors = ['k', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9']
×
122
    colors = get_trace_options(colors, running_trace_count, num_lines, repeat=True)
×
123

124
    # line thickness
125
    if line_opts.get('line_width') is not None:
×
126
        thick = line_opts['line_width']
×
127
    else:
128
        thick = [0.5]
×
129
    thick = get_trace_options(thick, running_trace_count, num_lines, repeat=True)
×
130

131
    # line style
132
    if line_opts.get('line_style_name') is not None:
×
133
        line_style_user = line_opts['line_style_name']
×
134

135
        # line_style_user should already be a list
136
        # handle legacy values
137
        line_style = []
×
138
        for linestyle in line_style_user:
×
139
            if linestyle == 'solid_line':
×
140
                line_style.append('solid')
×
141
            elif linestyle == 'dot':
×
142
                line_style.append('dotted')
×
143
            elif linestyle == 'dash':
×
144
                line_style.append('dashed')
×
145
            elif linestyle == 'dash_dot':
×
146
                line_style.append('dashdot')
×
147
            else:
148
                line_style.append(linestyle)
×
149
    else:
150
        line_style = ['solid']
×
151
    line_style = get_trace_options(line_style, running_trace_count, num_lines, repeat=True)
×
152

153
    symbols = False
×
154
    if line_opts.get('symbols') is not None:
×
155
        if line_opts['symbols']:
×
156
            symbols = True
×
157

158
    # create the plot
159
    line_options = {'alpha': alpha}
×
160

161
    marker_every = None
×
162
    if line_opts.get('markevery') is not None:
×
163
        marker_every = line_opts['markevery']
×
164
        marker_every = get_trace_options(marker_every, running_trace_count, num_lines, repeat=True)
×
165

166
    marker_sizes = None
×
167
    if line_opts.get('marker_size') is not None:
×
168
        marker_sizes = line_opts['marker_size']
×
169
        marker_sizes = get_trace_options(marker_sizes, running_trace_count, num_lines, repeat=True)
×
170

171
    # check for error data first
172
    if is_errorbar_plot:
×
173
        # error data provided
174
        line_options['yerr'] = var_data.dy[time_idxs]
×
175
        plotter = this_axis.errorbar
×
176
        if line_opts.get('ecolor') is not None:
×
177
            line_options['ecolor'] = line_opts['ecolor']
×
178
        if line_opts.get('elinewidth') is not None:
×
179
            line_options['elinewidth'] = line_opts['elinewidth']
×
180
        if line_opts.get('errorevery') is not None:
×
181
            line_options['errorevery'] = line_opts['errorevery']
×
182
        if line_opts.get('capsize') is not None:
×
183
            line_options['capsize'] = line_opts['capsize']
×
184
    else:
185
        # no error data provided
186
        plotter = this_axis.plot
×
187
        # Note: to turn off connecting lines in an error bar plot, do not use the
188
        # 'symbols' option.  Instead, set the line_options metadata to 'None' (as a string).
189
        if symbols:
×
190
            plotter = this_axis.scatter
×
191

192
    for line in range(0, num_lines):
×
193
        if colors is not None:
×
194
            color = colors[line]
×
195
        else:
196
            color = None
×
197

198
        if markers is not None:
×
199
            marker = markers[line]
×
200
        else:
201
            marker = None
×
202

203
        if marker_sizes is not None:
×
204
            # Note: scaling of marker sizes in scatter plots and line plots is different!
205
            # For line plot and scatter plot marker sizes to match, the line plot
206
            # marker size should be the square root of the scatter plot marker size.
207
            # Maybe that should be enforced here....???
208

209
            if symbols:
×
210
                line_options['s'] = marker_sizes[line]
×
211
            else:
212
                line_options['markersize'] = marker_sizes[line]
×
213

214
        if symbols:
×
215
            this_line_style='None'
×
216
        else:
217
            this_line_style=line_style[line]
×
218

219
        if marker_every is not None:
×
220
            line_options['markevery'] = marker_every[line]
×
221

222
        this_line = plotter(var_times, var_data.y[time_idxs] if num_lines == 1 else var_data.y[time_idxs, line], color=color,
×
223
                            linestyle=this_line_style, linewidth=thick[line], marker=marker, **line_options)
224

225
        if labels is not None:
×
226
            try:
×
227
                if isinstance(this_line, list):
×
228
                    this_line[0].set_label(labels[line])
×
229
                else:
230
                    this_line.set_label(labels[line])
×
231
            except IndexError:
×
232
                continue
×
233

234
    if labels is not None:
×
235
        legend = this_axis.legend(loc=legend_location, fontsize=legend_size, shadow=legend_shadow, title=legend_title,
×
236
                         labelcolor=legend_color, markerfirst=legend_markerfirst, markerscale=legend_markerscale,
237
                         facecolor=legend_facecolor, edgecolor=legend_edgecolor, frameon=legend_frameon, ncols=legend_ncols,
238
                         title_fontsize=legend_titlesize, bbox_to_anchor=bbox_to_anchor)
239
        try:
×
240
            handles = legend.legend_handles
×
241
        except AttributeError:
×
242
            handles = legend.legendHandles
×
243
        for legobj in handles:
×
244
            legobj.set_linewidth(legend_linewidth)
×
245

246
    return True
×
247

248
def get_trace_options(parent_array, start_trace=None, num_traces=1, repeat=False, fill=False, fillval=None):
1✔
249
    """ Get options for a set of traces from a parent array, extending or slicing as necessary to handle pseudovariable options
250

251
    Parameters
252
    -----------
253
        parent_array: str or list of str
254
            An array of option values to select from
255
        start_trace: int
256
            If set, we are processing a pseuodovariable, and this is the count of line traces processed so far for
257
            previous sub-variables in the current pseuodovariable.
258

259
            If parent_array is long enough (e.g. if set on the pseudovariable and intended to cover the complete
260
            set of traces), we take a slice from start_trace with num_traces entries.  If it matches
261
            the number of traces requested (e.g. parent array comes from this subvariable), we take it as-is.
262
            If there are fewer entries than num_traces (e.g. a single value intended to apply to all traces),
263
            we repeat parent_array or add fill until there are enough values to take a slice from start_trace.
264

265
            If None, we're just processing a regular variable, so we take values starting at zero (extending or filling
266
            as necessary)
267
            Default: None
268
        num_traces: int
269
            The number of traces in the current (sub-)variable.
270
        repeat: bool
271
            If True, extend the parent array by repetition if necessary. Defaults to False.
272
        fill: bool
273
            If True, extend the parent array by adding fill values. Defaults to False.
274
        fillval: Any
275
            If fill=True, values to append to parent_array to make enough entries. Defaults to None.
276

277
    Returns:
278
    --------
279
        list of option values with num_traces entries
280

281
    """
282
    if not isinstance(parent_array,list):
×
283
        parent_array=[parent_array]
×
284
    parent_length = len(parent_array)
×
285
    output_array = parent_array
×
286
    if start_trace is not None:
×
287
        end_trace = start_trace + num_traces
×
288
        if parent_length >= start_trace+num_traces:
×
289
            output_array = parent_array[start_trace:end_trace]
×
290
        elif parent_length == num_traces:
×
291
            output_array = parent_array
×
292
        else:
293
            if repeat:
×
294
                expansion_factor = int((end_trace/parent_length + 1))
×
295
                expanded_array = np.tile(parent_array,expansion_factor)
×
296
                output_array = expanded_array[start_trace:end_trace]
×
297
            elif fill:
×
298
                output_array = parent_array
×
299
                missing=num_traces-parent_length
×
300
                output_array.extend(np.tile([fillval],missing))
×
301
            else:
302
                logging.warning("Length of trace options (%d) smaller than number of traces (%d)",parent_length, num_traces)
×
303
    else:
304
        if len(parent_array) >= num_traces:
×
305
            output_array = parent_array[0:num_traces]
×
306
        else:
307
            if repeat:
×
308
                expansion_factor = int(num_traces/parent_length + 1)
×
309
                expanded_array = np.tile(parent_array,expansion_factor)
×
310
                output_array = expanded_array[0:num_traces]
×
311
            elif fill:
×
312
                output_array = parent_array
×
313
                missing = num_traces - parent_length
×
314
                output_array.extend(np.tile([fillval], missing))
×
315
            else:
316
                logging.warning("Length of trace options (%d) smaller than number of traces (%d)",parent_length, num_traces)
×
317
    return output_array
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc