mapdata 2.12.0__tar.gz → 2.13.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mapdata-2.12.0/mapdata.egg-info → mapdata-2.13.0}/PKG-INFO +1 -1
- {mapdata-2.12.0 → mapdata-2.13.0}/mapdata/mapdata.py +77 -14
- {mapdata-2.12.0 → mapdata-2.13.0/mapdata.egg-info}/PKG-INFO +1 -1
- {mapdata-2.12.0 → mapdata-2.13.0}/setup.py +1 -1
- {mapdata-2.12.0 → mapdata-2.13.0}/LICENSE.txt +0 -0
- {mapdata-2.12.0 → mapdata-2.13.0}/MANIFEST.in +0 -0
- {mapdata-2.12.0 → mapdata-2.13.0}/README.md +0 -0
- {mapdata-2.12.0 → mapdata-2.13.0}/mapdata/mapdata_2.py +0 -0
- {mapdata-2.12.0 → mapdata-2.13.0}/mapdata/mapdata_cli.py +0 -0
- {mapdata-2.12.0 → mapdata-2.13.0}/mapdata.egg-info/SOURCES.txt +0 -0
- {mapdata-2.12.0 → mapdata-2.13.0}/mapdata.egg-info/dependency_links.txt +0 -0
- {mapdata-2.12.0 → mapdata-2.13.0}/mapdata.egg-info/top_level.txt +0 -0
- {mapdata-2.12.0 → mapdata-2.13.0}/setup.cfg +0 -0
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
#
|
|
25
25
|
# ==================================================================
|
|
26
26
|
|
|
27
|
-
version = "2.
|
|
28
|
-
vdate = "2023-12-
|
|
27
|
+
version = "2.13.0"
|
|
28
|
+
vdate = "2023-12-30"
|
|
29
29
|
|
|
30
30
|
copyright = "2023"
|
|
31
31
|
|
|
@@ -460,14 +460,21 @@ class CsvFile(object):
|
|
|
460
460
|
|
|
461
461
|
|
|
462
462
|
def sort_columns(columns):
|
|
463
|
-
# Sorts a list of one or
|
|
463
|
+
# Sorts a list of one, two, or three sublists, where each sublist is a column. Rows are sorted by the first column.
|
|
464
464
|
# The returned value is also column-wise, but sorted by rows.
|
|
465
465
|
if len(columns) == 1:
|
|
466
466
|
return sorted(columns)
|
|
467
467
|
nrows = len(columns[0])
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
468
|
+
if len(columns) == 2:
|
|
469
|
+
rowdata = [[columns[0][i], columns[1][i]] for i in range(nrows)]
|
|
470
|
+
rowdata.sort()
|
|
471
|
+
return [[rowdata[i][0] for i in range(nrows)], [rowdata[i][1] for i in range(nrows)]]
|
|
472
|
+
else:
|
|
473
|
+
# len(columns) should be 3, though this is not checked
|
|
474
|
+
rowdata = [[columns[0][i], columns[1][i], columns[2][i]] for i in range(nrows)]
|
|
475
|
+
rowdata.sort()
|
|
476
|
+
return [[rowdata[i][0] for i in range(nrows)], [rowdata[i][1] for i in range(nrows)], [rowdata[i][2] for i in range(nrows)]]
|
|
477
|
+
|
|
471
478
|
|
|
472
479
|
def treeview_sort_column(tv, col, reverse):
|
|
473
480
|
# Sort columns in Tkinter Treeview. From https://stackoverflow.com/questions/1966929/tk-treeview-column-sort#1967793
|
|
@@ -1445,8 +1452,10 @@ class MapUI(object):
|
|
|
1445
1452
|
clone.ylog_var.set(plot_obj.ylog_var.get())
|
|
1446
1453
|
clone.x_sel["values"] = copy.copy(plot_obj.x_sel["values"])
|
|
1447
1454
|
clone.y_sel["values"] = copy.copy(plot_obj.y_sel["values"])
|
|
1455
|
+
clone.groupby_sel["values"] = copy.copy(plot_obj.groupby_sel["values"])
|
|
1448
1456
|
clone.x_sel["state"] = plot_obj.x_sel["state"]
|
|
1449
1457
|
clone.y_sel["state"] = plot_obj.y_sel["state"]
|
|
1458
|
+
clone.groupby_sel["state"] = plot_obj.groupby_sel["state"]
|
|
1450
1459
|
clone.xlog_ck["state"] = plot_obj.xlog_ck["state"]
|
|
1451
1460
|
clone.ylog_ck["state"] = plot_obj.ylog_ck["state"]
|
|
1452
1461
|
clone.data_btn["state"] = plot_obj.data_btn["state"]
|
|
@@ -2788,7 +2797,7 @@ class PlotDialog(object):
|
|
|
2788
2797
|
self.plot_title = None
|
|
2789
2798
|
# For histogram
|
|
2790
2799
|
self.bins = 10
|
|
2791
|
-
# For groups at Jenks breaks on Q-Q plots
|
|
2800
|
+
# For display of groups at Jenks breaks on Q-Q plots
|
|
2792
2801
|
self.qq_groups = False
|
|
2793
2802
|
|
|
2794
2803
|
def set_autoupdate():
|
|
@@ -2818,6 +2827,7 @@ class PlotDialog(object):
|
|
|
2818
2827
|
self.type_sel = ttk.Combobox(ctrl_frame, state="readonly", textvariable=self.type_var, width=20, height=15,
|
|
2819
2828
|
values=["Box plot", "Breaks groups", "Breaks optimum", "Category counts", "Categorical KD plot", "Categorical stripchart", "Empirical CDF", "Histogram", "Kernel density (KD) plot", "Line plot", "Min-max plot", "Normal Q-Q plot", "Scatter plot", "Violin plot", "Y range plot"])
|
|
2820
2829
|
self.type_sel.grid(row=0, column=1, columnspan=2, sticky=tk.W, padx=(3,6), pady=(3,3))
|
|
2830
|
+
self.type_sel["state"] = "normal"
|
|
2821
2831
|
self.type_sel.bind("<<ComboboxSelected>>", self.set_xy)
|
|
2822
2832
|
|
|
2823
2833
|
self.sel_only_var = tk.StringVar(ctrl_frame, "0")
|
|
@@ -2833,14 +2843,14 @@ class PlotDialog(object):
|
|
|
2833
2843
|
self.x_var = tk.StringVar(ctrl_frame, "")
|
|
2834
2844
|
x_lbl = ttk.Label(ctrl_frame, text="X column:")
|
|
2835
2845
|
x_lbl.grid(row=0, column=3, sticky=tk.E, padx=(6,3), pady=(3,3))
|
|
2836
|
-
self.x_sel = ttk.Combobox(ctrl_frame, state="disabled", textvariable=self.x_var, width=
|
|
2846
|
+
self.x_sel = ttk.Combobox(ctrl_frame, state="disabled", textvariable=self.x_var, width=24)
|
|
2837
2847
|
self.x_sel.grid(row=0, column=4, sticky=tk.W, padx=(3,6), pady=(3,3))
|
|
2838
2848
|
self.x_sel.bind("<<ComboboxSelected>>", self.x_changed)
|
|
2839
2849
|
|
|
2840
2850
|
self.y_var = tk.StringVar(ctrl_frame, "")
|
|
2841
2851
|
y_lbl = ttk.Label(ctrl_frame, text="Y column:")
|
|
2842
2852
|
y_lbl.grid(row=1, column=3, sticky=tk.E, padx=(6,3), pady=(3,3))
|
|
2843
|
-
self.y_sel = ttk.Combobox(ctrl_frame, state="disabled", textvariable=self.y_var, width=
|
|
2853
|
+
self.y_sel = ttk.Combobox(ctrl_frame, state="disabled", textvariable=self.y_var, width=24)
|
|
2844
2854
|
self.y_sel.grid(row=1, column=4, sticky=tk.W, padx=(3,6), pady=(3,3))
|
|
2845
2855
|
self.y_sel.bind("<<ComboboxSelected>>", self.y_changed)
|
|
2846
2856
|
|
|
@@ -2854,6 +2864,13 @@ class PlotDialog(object):
|
|
|
2854
2864
|
onvalue="1", offvalue="0")
|
|
2855
2865
|
self.ylog_ck.grid(row=1, column=5, sticky=tk.W, padx=(6,6), pady=(3,3))
|
|
2856
2866
|
|
|
2867
|
+
self.groupby_var = tk.StringVar(ctrl_frame, "")
|
|
2868
|
+
groupby_lbl = ttk.Label(ctrl_frame, text="Group by:")
|
|
2869
|
+
groupby_lbl.grid(row=2, column=3, sticky=tk.E, padx=(6,3), pady=(3,3))
|
|
2870
|
+
self.groupby_sel = ttk.Combobox(ctrl_frame, state="disabled", textvariable=self.groupby_var, width=24)
|
|
2871
|
+
self.groupby_sel.grid(row=2, column=4, sticky=tk.W, padx=(3,6), pady=(3,3))
|
|
2872
|
+
self.groupby_sel.bind("<<ComboboxSelected>>", self.groupby_changed)
|
|
2873
|
+
|
|
2857
2874
|
# Plot
|
|
2858
2875
|
self.content_frame = tk.Frame(self.dlg, borderwidth=3, relief=tk.RIDGE)
|
|
2859
2876
|
self.content_frame.grid(row=2, column=0, sticky=tk.NSEW)
|
|
@@ -2956,8 +2973,12 @@ class PlotDialog(object):
|
|
|
2956
2973
|
self.ylog_ck["state"] = "normal"
|
|
2957
2974
|
self.q_redraw(args)
|
|
2958
2975
|
|
|
2976
|
+
def groupby_changed(self, *args):
|
|
2977
|
+
self.q_redraw(args)
|
|
2978
|
+
|
|
2959
2979
|
def set_xy(self, *args):
|
|
2960
2980
|
# Enable X and Y value selection, and set Combobox values based on plot type and column types.
|
|
2981
|
+
# Also sets the groupby Combobox values if applicable.
|
|
2961
2982
|
self.plotfig.clear()
|
|
2962
2983
|
self.plot_title = None
|
|
2963
2984
|
self.dlg.bind("<Alt-b>")
|
|
@@ -2984,17 +3005,21 @@ class PlotDialog(object):
|
|
|
2984
3005
|
date_columns.sort()
|
|
2985
3006
|
self.x_var.set('')
|
|
2986
3007
|
self.y_var.set('')
|
|
3008
|
+
self.groupby_var.set('')
|
|
2987
3009
|
self.xlog_ck["state"] = "normal"
|
|
2988
3010
|
self.ylog_ck["state"] = "normal"
|
|
2989
3011
|
self.x_sel["state"] = "readonly"
|
|
2990
3012
|
self.y_sel["state"] = "readonly"
|
|
3013
|
+
self.groupby_sel["state"] = "readonly"
|
|
2991
3014
|
plot_type = self.type_var.get()
|
|
2992
3015
|
if plot_type == "Category counts":
|
|
3016
|
+
self.x_sel["state"] = "normal"
|
|
2993
3017
|
self.x_sel["values"] = categ_columns
|
|
2994
3018
|
self.xlog_ck["state"] = "disabled"
|
|
2995
3019
|
self.y_sel["state"] = "disabled"
|
|
2996
3020
|
self.ylog_ck["state"] = "disabled"
|
|
2997
3021
|
elif plot_type in ("Histogram", "Empirical CDF", "Kernel density (KD) plot", "Normal Q-Q plot", "Breaks groups", "Breaks optimum"):
|
|
3022
|
+
self.x_sel["state"] = "normal"
|
|
2998
3023
|
self.x_sel["values"] = numeric_columns
|
|
2999
3024
|
self.y_sel["state"] = "disabled"
|
|
3000
3025
|
self.ylog_ck["state"] = "disabled"
|
|
@@ -3005,16 +3030,24 @@ class PlotDialog(object):
|
|
|
3005
3030
|
elif plot_type in ("Box plot", "Categorical KD plot", "Categorical stripchart", "Violin plot"):
|
|
3006
3031
|
xcols = list(set(categ_columns) | set(date_columns))
|
|
3007
3032
|
xcols.sort()
|
|
3033
|
+
self.x_sel["state"] = "normal"
|
|
3008
3034
|
self.x_sel["values"] = xcols
|
|
3009
3035
|
self.xlog_ck["state"] = "disabled"
|
|
3010
3036
|
self.y_sel["values"] = numeric_columns
|
|
3011
3037
|
elif plot_type == "Min-max plot":
|
|
3038
|
+
self.x_sel["state"] = "normal"
|
|
3012
3039
|
self.x_sel["values"] = quant_columns
|
|
3040
|
+
self.y_sel["state"] = "normal"
|
|
3013
3041
|
self.y_sel["values"] = categ_columns2
|
|
3014
3042
|
self.ylog_ck["state"] = "disabled"
|
|
3015
3043
|
else:
|
|
3044
|
+
self.x_sel["state"] = "normal"
|
|
3016
3045
|
self.x_sel["values"] = quant_columns
|
|
3046
|
+
self.y_sel["state"] = "normal"
|
|
3017
3047
|
self.y_sel["values"] = quant_columns
|
|
3048
|
+
if plot_type in ("Scatter plot", "Line plot"):
|
|
3049
|
+
self.groupby_sel["state"] = "normal"
|
|
3050
|
+
self.groupby_sel["values"] = [''] + categ_columns2
|
|
3018
3051
|
|
|
3019
3052
|
def q_redraw(self, get_data=True, *args):
|
|
3020
3053
|
# Conditionally (re)draw the plot.
|
|
@@ -3041,6 +3074,8 @@ class PlotDialog(object):
|
|
|
3041
3074
|
column_list = [self.x_var.get()]
|
|
3042
3075
|
if self.y_var.get() != '':
|
|
3043
3076
|
column_list.append(self.y_var.get())
|
|
3077
|
+
if self.groupby_var.get() != '':
|
|
3078
|
+
column_list.append(self.groupby_var.get())
|
|
3044
3079
|
# Get either only the selected data or all data.
|
|
3045
3080
|
if self.sel_only_var.get() == "1":
|
|
3046
3081
|
dataset = self.parent.get_sel_data(column_list)
|
|
@@ -3082,6 +3117,8 @@ class PlotDialog(object):
|
|
|
3082
3117
|
# Set data labels
|
|
3083
3118
|
if self.y_var.get() != '':
|
|
3084
3119
|
self.data_labels = [self.x_var.get(), self.y_var.get()]
|
|
3120
|
+
if self.groupby_var.get() != '':
|
|
3121
|
+
self.data_labels.append(self.groupby_var.get())
|
|
3085
3122
|
else:
|
|
3086
3123
|
self.data_labels = [self.x_var.get()]
|
|
3087
3124
|
# Log-transform data if specified.
|
|
@@ -3158,7 +3195,7 @@ class PlotDialog(object):
|
|
|
3158
3195
|
self.plot_data_labels = [self.data_labels[0], "Cumulative frequency"]
|
|
3159
3196
|
elif plot_type == "Kernel density (KD) plot":
|
|
3160
3197
|
self.plot_data = self.dataset
|
|
3161
|
-
|
|
3198
|
+
self.plot_data_labels = [self.x_var.get()]
|
|
3162
3199
|
elif plot_type == "Min-max plot":
|
|
3163
3200
|
# Min and max X for each Y
|
|
3164
3201
|
y_vals = list(set(self.dataset[1]))
|
|
@@ -3209,10 +3246,16 @@ class PlotDialog(object):
|
|
|
3209
3246
|
self.plot_data_labels = [self.data_labels[0], self.data_labels[1] + " min", self.data_labels[1] + " max"]
|
|
3210
3247
|
elif plot_type == "Line plot":
|
|
3211
3248
|
# Sort by X
|
|
3212
|
-
|
|
3249
|
+
if self.groupby_var.get() == '':
|
|
3250
|
+
ds = list(zip(self.dataset[0], self.dataset[1]))
|
|
3251
|
+
else:
|
|
3252
|
+
ds = list(zip(self.dataset[0], self.dataset[1], self.dataset[2]))
|
|
3213
3253
|
ds.sort()
|
|
3214
3254
|
ds2 = list(zip(*ds))
|
|
3215
|
-
self.
|
|
3255
|
+
if self.groupby_var.get() == '':
|
|
3256
|
+
self.plot_data = [list(ds2[0]), list(ds2[1])]
|
|
3257
|
+
else:
|
|
3258
|
+
self.plot_data = [list(ds2[0]), list(ds2[1]), list(ds2[2])]
|
|
3216
3259
|
self.plot_data_labels = self.data_labels
|
|
3217
3260
|
elif plot_type in ("Histogram", "Scatter plot", "Y range plot"):
|
|
3218
3261
|
# No special preparation
|
|
@@ -3232,11 +3275,31 @@ class PlotDialog(object):
|
|
|
3232
3275
|
self.plot_axes.set_xlabel(self.x_var.get())
|
|
3233
3276
|
self.plot_axes.set_ylabel("Counts")
|
|
3234
3277
|
elif plot_type == "Scatter plot":
|
|
3235
|
-
self.
|
|
3278
|
+
if self.groupby_var.get() == '':
|
|
3279
|
+
self.plot_axes.scatter(self.plot_data[0], self.plot_data[1])
|
|
3280
|
+
else:
|
|
3281
|
+
groups = list(set(self.plot_data[2]))
|
|
3282
|
+
groups.sort()
|
|
3283
|
+
datarows = len(self.plot_data[0])
|
|
3284
|
+
for g in groups:
|
|
3285
|
+
pdx = [self.plot_data[0][i] for i in range(datarows) if self.plot_data[2][i] == g]
|
|
3286
|
+
pdy = [self.plot_data[1][i] for i in range(datarows) if self.plot_data[2][i] == g]
|
|
3287
|
+
self.plot_axes.plot(pdx, pdy, marker='o', linestyle='', label=g)
|
|
3288
|
+
self.plot_axes.legend()
|
|
3236
3289
|
self.plot_axes.set_xlabel(self.plot_data_labels[0])
|
|
3237
3290
|
self.plot_axes.set_ylabel(self.plot_data_labels[1])
|
|
3238
3291
|
elif plot_type == "Line plot":
|
|
3239
|
-
self.
|
|
3292
|
+
if self.groupby_var.get() == '':
|
|
3293
|
+
self.plot_axes.plot(self.plot_data[0], self.plot_data[1])
|
|
3294
|
+
else:
|
|
3295
|
+
groups = list(set(self.plot_data[2]))
|
|
3296
|
+
groups.sort()
|
|
3297
|
+
datarows = len(self.plot_data[0])
|
|
3298
|
+
for g in groups:
|
|
3299
|
+
pdx = [self.plot_data[0][i] for i in range(datarows) if self.plot_data[2][i] == g]
|
|
3300
|
+
pdy = [self.plot_data[1][i] for i in range(datarows) if self.plot_data[2][i] == g]
|
|
3301
|
+
self.plot_axes.plot(pdx, pdy, label=g)
|
|
3302
|
+
self.plot_axes.legend()
|
|
3240
3303
|
self.plot_axes.set_xlabel(self.plot_data_labels[0])
|
|
3241
3304
|
self.plot_axes.set_ylabel(self.plot_data_labels[1])
|
|
3242
3305
|
elif plot_type == "Breaks groups":
|
|
@@ -5,7 +5,7 @@ with io.open('README.md', encoding='utf-8') as f:
|
|
|
5
5
|
long_description = f.read()
|
|
6
6
|
|
|
7
7
|
setuptools.setup(name='mapdata',
|
|
8
|
-
version='2.
|
|
8
|
+
version='2.13.0',
|
|
9
9
|
description="An interactive map and table explorer for geographic coordinates in a spreadsheet, CSV file, or database",
|
|
10
10
|
author='Dreas Nielsen',
|
|
11
11
|
author_email='dreas.nielsen@gmail.com',
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|