mapdata 2.11.0__tar.gz → 2.12.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mapdata
3
- Version: 2.11.0
3
+ Version: 2.12.0
4
4
  Summary: An interactive map and table explorer for geographic coordinates in a spreadsheet, CSV file, or database
5
5
  Home-page: https://osdn.net/project/mapdata/
6
6
  Author: Dreas Nielsen
@@ -24,8 +24,8 @@
24
24
  #
25
25
  # ==================================================================
26
26
 
27
- version = "2.11.0"
28
- vdate = "2023-09-16"
27
+ version = "2.12.0"
28
+ vdate = "2023-12-28"
29
29
 
30
30
  copyright = "2023"
31
31
 
@@ -459,6 +459,16 @@ class CsvFile(object):
459
459
  return self
460
460
 
461
461
 
462
+ def sort_columns(columns):
463
+ # Sorts a list of one or two sublists, where each sublist is a column. Rows are sorted by the first column.
464
+ # The returned value is also column-wise, but sorted by rows.
465
+ if len(columns) == 1:
466
+ return sorted(columns)
467
+ nrows = len(columns[0])
468
+ rowdata = [[columns[0][i], columns[1][i]] for i in range(nrows)]
469
+ rowdata.sort()
470
+ return [[rowdata[i][0] for i in range(nrows)], [rowdata[i][1] for i in range(nrows)]]
471
+
462
472
  def treeview_sort_column(tv, col, reverse):
463
473
  # Sort columns in Tkinter Treeview. From https://stackoverflow.com/questions/1966929/tk-treeview-column-sort#1967793
464
474
  colvals = [(tv.set(k, col), k) for k in tv.get_children()]
@@ -2805,8 +2815,8 @@ class PlotDialog(object):
2805
2815
  self.type_var = tk.StringVar(ctrl_frame, "")
2806
2816
  type_lbl = ttk.Label(ctrl_frame, text="Plot type:")
2807
2817
  type_lbl.grid(row=0, column=0, sticky=tk.E, padx=(6,3), pady=(3,3))
2808
- self.type_sel = ttk.Combobox(ctrl_frame, state="readonly", textvariable=self.type_var, width=20,
2809
- values=["Box plot", "Breaks groups", "Breaks optimum", "Category counts", "Categorical KD plot", "Categorical stripchart", "Empirical CDF", "Histogram", "Kernel density (KD) plot", "Line plot", "Normal Q-Q plot", "Scatter plot", "Violin plot", "Y range plot"])
2818
+ self.type_sel = ttk.Combobox(ctrl_frame, state="readonly", textvariable=self.type_var, width=20, height=15,
2819
+ 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"])
2810
2820
  self.type_sel.grid(row=0, column=1, columnspan=2, sticky=tk.W, padx=(3,6), pady=(3,3))
2811
2821
  self.type_sel.bind("<<ComboboxSelected>>", self.set_xy)
2812
2822
 
@@ -2940,7 +2950,7 @@ class PlotDialog(object):
2940
2950
 
2941
2951
  def y_changed(self, *args):
2942
2952
  plot_type = self.type_var.get()
2943
- if plot_type in ("Category counts", "Histogram", "Empirical CDF"):
2953
+ if plot_type in ("Category counts", "Histogram", "Empirical CDF", "Min-max plot"):
2944
2954
  self.ylog_ck["state"] = "disabled"
2945
2955
  else:
2946
2956
  self.ylog_ck["state"] = "normal"
@@ -2960,8 +2970,11 @@ class PlotDialog(object):
2960
2970
  self.plot_data_labels = None
2961
2971
  self.data_btn["state"] = "disabled"
2962
2972
  self.plot_data_btn["state"] = "disabled"
2973
+ # Category columns. Does not include date columns for most uses, but may include dates for some.
2963
2974
  categ_columns = [c[0] for c in self.column_specs if c[1] in ("string", "boolean")]
2964
2975
  categ_columns.sort()
2976
+ categ_columns2 = [c[0] for c in self.column_specs if c[1] in ("string", "boolean", "date")]
2977
+ categ_columns2.sort()
2965
2978
  # quant_columns includes date and timestamp columns
2966
2979
  quant_columns = [c[0] for c in self.column_specs if c[1] in ("int", "float", "date", "timestamp", "timestamptz")]
2967
2980
  quant_columns.sort()
@@ -2990,9 +3003,15 @@ class PlotDialog(object):
2990
3003
  if plot_type == "Normal Q-Q plot":
2991
3004
  self.dlg.bind("<Alt-g>", self.show_groups)
2992
3005
  elif plot_type in ("Box plot", "Categorical KD plot", "Categorical stripchart", "Violin plot"):
2993
- self.x_sel["values"] = list(set(categ_columns) | set(date_columns))
3006
+ xcols = list(set(categ_columns) | set(date_columns))
3007
+ xcols.sort()
3008
+ self.x_sel["values"] = xcols
2994
3009
  self.xlog_ck["state"] = "disabled"
2995
3010
  self.y_sel["values"] = numeric_columns
3011
+ elif plot_type == "Min-max plot":
3012
+ self.x_sel["values"] = quant_columns
3013
+ self.y_sel["values"] = categ_columns2
3014
+ self.ylog_ck["state"] = "disabled"
2996
3015
  else:
2997
3016
  self.x_sel["values"] = quant_columns
2998
3017
  self.y_sel["values"] = quant_columns
@@ -3004,7 +3023,7 @@ class PlotDialog(object):
3004
3023
  "Normal Q-Q plot", "Breaks groups", "Breaks optimum", "Histogram") \
3005
3024
  and self.x_var.get() != '') \
3006
3025
  or (plot_type in ("Scatter plot", "Line plot", "Box plot", "Categorical KD plot", "Categorical stripchart", \
3007
- "Violin plot", "Y range plot") and self.x_var.get() != '' and self.y_var.get() != '')
3026
+ "Min-max plot", "Violin plot", "Y range plot") and self.x_var.get() != '' and self.y_var.get() != '')
3008
3027
  if can_redraw:
3009
3028
  self.plotfig.clear()
3010
3029
  self.plot_axes = self.plotfig.add_subplot(111)
@@ -3022,6 +3041,7 @@ class PlotDialog(object):
3022
3041
  column_list = [self.x_var.get()]
3023
3042
  if self.y_var.get() != '':
3024
3043
  column_list.append(self.y_var.get())
3044
+ # Get either only the selected data or all data.
3025
3045
  if self.sel_only_var.get() == "1":
3026
3046
  dataset = self.parent.get_sel_data(column_list)
3027
3047
  else:
@@ -3057,6 +3077,8 @@ class PlotDialog(object):
3057
3077
  cast_fn = data_type_cast_fn(y_data_type)
3058
3078
  for i in range(len(clean_data[1])):
3059
3079
  clean_data[1][i] = cast_fn(clean_data[1][i])
3080
+ # Sort the dataset by X values
3081
+ clean_data = sort_columns(clean_data)
3060
3082
  # Set data labels
3061
3083
  if self.y_var.get() != '':
3062
3084
  self.data_labels = [self.x_var.get(), self.y_var.get()]
@@ -3106,6 +3128,7 @@ class PlotDialog(object):
3106
3128
  elif plot_type in ("Box plot", "Categorical KD plot", "Categorical stripchart", "Violin plot"):
3107
3129
  # A list of Y values for each X value
3108
3130
  x_vals = list(set(self.dataset[0]))
3131
+ x_vals.sort()
3109
3132
  ds = list(zip(self.dataset[0], self.dataset[1]))
3110
3133
  plot_data = []
3111
3134
  for x in x_vals:
@@ -3135,7 +3158,24 @@ class PlotDialog(object):
3135
3158
  self.plot_data_labels = [self.data_labels[0], "Cumulative frequency"]
3136
3159
  elif plot_type == "Kernel density (KD) plot":
3137
3160
  self.plot_data = self.dataset
3138
- self.plot_data_labels = [self.x_var.get()]
3161
+ #self.plot_data_labels = [self.x_var.get()]
3162
+ elif plot_type == "Min-max plot":
3163
+ # Min and max X for each Y
3164
+ y_vals = list(set(self.dataset[1]))
3165
+ y_vals.sort()
3166
+ plotdata = dict(zip(y_vals, [[None, None] for _ in y_vals]))
3167
+ for i in range(len(self.dataset[1])):
3168
+ x = self.dataset[0][i]
3169
+ y = self.dataset[1][i]
3170
+ x_vals = plotdata[y]
3171
+ if x_vals[0] is None or x < x_vals[0]:
3172
+ plotdata[y][0] = x
3173
+ if x_vals[1] is None or x > x_vals[1]:
3174
+ plotdata[y][1] = x
3175
+ x1 = [plotdata[y][0] for y in y_vals]
3176
+ x2 = [plotdata[y][1] for y in y_vals]
3177
+ self.plot_data = [y_vals, x1, x2]
3178
+ self.plot_data_labels = [self.data_labels[1], self.data_labels[0] + " min", self.data_labels[0] + " max"]
3139
3179
  elif plot_type == "Normal Q-Q plot":
3140
3180
  x_vals = copy.copy(self.dataset[0])
3141
3181
  x_vals.sort()
@@ -3154,8 +3194,7 @@ class PlotDialog(object):
3154
3194
  # Min and max Y for each X
3155
3195
  x_vals = list(set(self.dataset[0]))
3156
3196
  x_vals.sort()
3157
- y_vals = [[None, None]] * len(x_vals)
3158
- plotdata = dict(zip(x_vals, y_vals))
3197
+ plotdata = dict(zip(x_vals, [[None, None] for i in x_vals]))
3159
3198
  for i in range(len(self.dataset[0])):
3160
3199
  x = self.dataset[0][i]
3161
3200
  y = self.dataset[1][i]
@@ -3208,7 +3247,7 @@ class PlotDialog(object):
3208
3247
  ticks.insert(0,0)
3209
3248
  ticks.append(ticks[-1]+1)
3210
3249
  self.plot_axes.set_xticks(ticks)
3211
- lbls = self.plot_data_labels
3250
+ lbls = copy.copy(self.plot_data_labels)
3212
3251
  lbls.insert(0, "")
3213
3252
  lbls.append("")
3214
3253
  self.plot_axes.set_xticklabels(lbls)
@@ -3227,6 +3266,13 @@ class PlotDialog(object):
3227
3266
  sns.kdeplot({self.x_var.get(): self.dataset[0]}, x=self.x_var.get(), fill=True, ax=self.plot_axes)
3228
3267
  self.plot_axes.set_xlabel(self.x_var.get())
3229
3268
  self.plot_axes.set_ylabel("Density")
3269
+ elif plot_type == "Min-max plot":
3270
+ self.plot_axes.hlines(self.plot_data[0], self.plot_data[1], self.plot_data[2], linewidths=5.0)
3271
+ if self.xlog_ck["state"] != "disabled" and self.xlog_var.get() == "1":
3272
+ self.plot_axes.set_xlabel("Log10 of " + self.x_var.get())
3273
+ else:
3274
+ self.plot_axes.set_xlabel(self.x_var.get())
3275
+ self.plot_axes.set_ylabel(self.plot_data_labels[0])
3230
3276
  elif plot_type == "Normal Q-Q plot":
3231
3277
  if self.qq_groups:
3232
3278
  self.plot_axes.scatter(self.plot_data[2], self.plot_data[1], c=self.plot_data[3], cmap="tab10")
@@ -3240,14 +3286,22 @@ class PlotDialog(object):
3240
3286
  elif plot_type == "Y range plot":
3241
3287
  self.plot_axes.fill_between(self.plot_data[0], self.plot_data[1], self.plot_data[2])
3242
3288
  self.plot_axes.set_xlabel(self.x_var.get())
3243
- self.plot_axes.set_ylabel(self.y_var.get())
3289
+ if self.xlog_ck["state"] != "disabled" and self.xlog_var.get() == "1":
3290
+ self.plot_axes.set_xlabel("Log10 of " + self.x_var.get())
3291
+ else:
3292
+ self.plot_axes.set_xlabel(self.x_var.get())
3293
+ if self.ylog_ck["state"] != "disabled" and self.ylog_var.get() == "1":
3294
+ self.plot_axes.set_ylabel("Log10 of " + self.y_var.get())
3295
+ else:
3296
+ self.plot_axes.set_ylabel(self.y_var.get())
3244
3297
  elif plot_type == "Box plot":
3245
3298
  self.plot_axes.boxplot(self.plot_data, labels=self.plot_data_labels)
3246
3299
  self.plot_axes.set_xlabel(self.x_var.get())
3247
3300
  self.plot_axes.set_ylabel(self.data_labels[1])
3248
3301
  elif plot_type == "Categorical KD plot":
3249
3302
  sns.kdeplot({self.x_var.get(): self.dataset[0], self.y_var.get(): self.dataset[1]},
3250
- x=self.y_var.get(), hue=self.x_var.get(), multiple="layer", fill=True, alpha=0.35, ax=self.plot_axes)
3303
+ x=self.y_var.get(), hue=self.x_var.get(), multiple="layer", fill=True, alpha=0.35, ax=self.plot_axes,
3304
+ warn_singular=False)
3251
3305
  self.plot_axes.set_xlabel(self.y_var.get())
3252
3306
  self.plot_axes.set_ylabel("Density")
3253
3307
  elif plot_type == "Categorical stripchart":
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mapdata
3
- Version: 2.11.0
3
+ Version: 2.12.0
4
4
  Summary: An interactive map and table explorer for geographic coordinates in a spreadsheet, CSV file, or database
5
5
  Home-page: https://osdn.net/project/mapdata/
6
6
  Author: Dreas Nielsen
@@ -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.11.0',
8
+ version='2.12.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