如何绘制一个国家(或大陆)的地图并为其一部分着色?

如何绘制一个国家(或大陆)的地图并为其一部分着色?

在我的作业中,我想绘制一张澳大利亚地图,标出各州的边界(并在上面写上每个州的名称):

在此处输入图片描述

我想知道是否有办法使用来实现这些能力tikz

答案1

如果你想将它用于你的作业的话,我认为这是一个迟来的答案……

在此处输入图片描述

代码基于一组(大量)点。我有一个小的 Python 程序,从地图开始,我可以用它来构造边界点。我应该将它分别用于地图的每个区域,但这个想法来得太晚了。因此,结果只是一组无序的点,除了大陆边界之外。

\documentclass[margin=1in]{standalone}
\usepackage{tikz}
\usetikzlibrary{math, calc}

\begin{document}

\tikzmath{%
  coordinate \A{1}, \A{2}, \B{1}, \B{2}, \T{1}, \T{2};
  coordinate \C, \D, \E, \F, \G, \H, \I;
  \A{1} = (111pt, -441pt);
  \A{2} = (133pt, -458pt);
  \A{3} = (160pt, -463pt);
  \A{4} = (189pt, -437pt);
  \A{5} = (243pt, -438pt);
  \A{6} = (281pt, -405pt);
  \A{7} = (319pt, -397pt);
  \A{8} = (362pt, -393pt);
  \A{9} = (393pt, -404pt);
  \A{10} = (422pt, -458pt);
  \A{11} = (450pt, -428pt);
  \A{12} = (444pt, -459pt);
  \A{13} = (458pt, -455pt);
  \A{14} = (464pt, -472pt);
  \A{15} = (475pt, -471pt);
  \A{16} = (493pt, -522pt);
  \A{17} = (543pt, -541pt);
  \A{18} = (563pt, -524pt);
  \A{19} = (581pt, -541pt);
  \A{20} = (599pt, -530pt);
  \A{21} = (604pt, -519pt);
  \A{22} = (631pt, -516pt);
  \A{23} = (652pt, -450pt);
  \A{24} = (676pt, -405pt);
  \A{25} = (694pt, -330pt);
  \A{26} = (686pt, -279pt);
  \A{27} = (668pt, -251pt);
  \A{28} = (651pt, -237pt);
  \A{29} = (648pt, -220pt);
  \A{30} = (630pt, -208pt);
  \A{31} = (621pt, -178pt);
  \A{32} = (588pt, -158pt);
  \A{33} = (565pt, -82pt);
  \A{34} = (551pt, -73pt);
  \A{35} = (544pt, -72pt);
  \A{36} = (542pt, -42pt);
  \A{37} = (522pt, -11pt);
  \A{38} = (509pt, -55pt);
  \A{39} = (509pt, -99pt);
  \A{40} = (494pt, -128pt);
  \A{41} = (474pt, -119pt);
  \A{42} = (428pt, -85pt);
  \A{43} = (442pt, -40pt);
  \A{44} = (379pt, -24pt);
  \A{45} = (349pt, -41pt);
  \A{46} = (327pt, -76pt);
  \A{47} = (290pt, -64pt);
  \A{48} = (268pt, -84pt);
  \A{49} = (247pt, -112pt);
  \A{50} = (227pt, -116pt);
  \A{51} = (210pt, -155pt);
  \A{52} = (178pt, -175pt);
  \A{53} = (138pt, -184pt);
  \A{54} = (98pt, -212pt);
  \A{55} = (92pt, -261pt);
  \A{56} = (97pt, -300pt);
  \A{57} = (123pt, -389pt);
  \A{58} = (124pt, -420pt);
  \A{59} = (111pt, -441pt);
  \T{1} = (559pt, -583pt);
  \T{2} = (585pt, -591pt);
  \T{3} = (610pt, -585pt);
  \T{4} = (612pt, -608pt);
  \T{5} = (599pt, -634pt);
  \T{6} = (592pt, -644pt);
  \T{7} = (579pt, -644pt);
  \T{8} = (566pt, -623pt);
  \T{9} = (566pt, -608pt);
  \T{10} = (559pt, -583pt);
  \B{1} = (634pt, -509pt);
  \B{2} = (614pt, -493pt);
  \B{3} = (604pt, -479pt);
  \B{4} = (570pt, -480pt);
  \B{5} = (558pt, -482pt);
  \B{6} = (537pt, -452pt);
  \B{7} = (523pt, -447pt);
  \B{8} = (504pt, -439pt);
  \B{9} = (504pt, -337pt);
  \B{10} = (620pt, -336pt);
  \B{11} = (635pt, -328pt);
  \B{12} = (651pt, -328pt);
  \B{13} = (659pt, -337pt);
  \B{14} = (694pt, -327pt);
  \C = (504pt, -281pt);
  \D = (460pt, -109pt);
  \E = (461pt, -281pt);
  \F = (324pt, -281pt);
  \G = (324pt, -397pt);
  \H = (504pt, -527pt);
  \I = (324pt, -75pt);
}
\begin{tikzpicture}[xscale=.6, yscale=.55]
  % australia
  \draw (\A{1})
  \foreach \i in {2, 3, ..., 59}{ -- (\A{\i}) } -- cycle;

  % t
  \draw (\T{1})
  \foreach \i in {2, 3, ..., 10}{ -- (\T{\i}) } -- cycle;

  % new s w
  \draw (\B{1})
  \foreach \i in {2, 3, ..., 14}{ -- (\B{\i}) }
  -- (\A{25}) -- (\A{24}) -- (\A{23}) -- cycle;

  % q
  \draw (\B{14}) -- (\A{26})
  \foreach \i in {27, ..., 41}{ -- (\A{\i}) }
  -- (\D) -- (\E) -- (\C)
  \foreach \i in {9, ..., 13}{ -- (\B{\i}) }
  -- cycle;

  % v
  \draw (\B{1})
  \foreach \i in {2, 3, ..., 9}{ -- (\B{\i}) }
  -- (\H)
  \foreach \i in {17, ..., 22}{ -- (\A{\i}) } -- cycle;

  % s a
  \draw (\H) -- (\C) -- (\F) -- (\G)
  \foreach \i in {8, ..., 16}{ -- (\A{\i})} -- cycle;

  % n t
  \draw (\D) -- (\E) -- (\F) -- (\I)
  \foreach \i in {46, ..., 42}{ -- (\A{\i})} -- cycle;

  % w a
  \draw (\G) -- (\I)
  \foreach \i in {47, ..., 59}{ -- (\A{\i})}
  \foreach \i in {1, ..., 7}{ -- (\A{\i})} -- cycle;
\end{tikzpicture}

\end{document}

我在下面添加了 Python 程序。执行时,它会启动一个带有两个轴的图形窗口:左侧带有按钮,右侧带有我们想要“绘制”的地图。最后两行适用于文件澳大利亚.jpg必须存在于同一目录中。使用它后,至少会创建一个文件“australia.dat”...

该程序处理仅有的一条连通曲线(我认为)可以随意丰富。但谁知道呢!

'''
Construct a closed polygonal curve that enclosed a continent (country 
or whatever).  Then, the curve is enriched with vertices such that, 
at the limit it would coincide with the continent.

The curves (contour curves) can be put together to form an animation.

Rem. When launched, a jpg file must exist in the same directory. 
'''
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib import patches
from matplotlib.widgets import Button
from matplotlib import animation
from matplotlib.animation import FuncAnimation

import os.path
import copy
import time

#####################################################################

class ContourCurves():
    
    _fig = None  # figure; contains buttons and axes for the map
    _axes = None  # Axes on which the contour curves are constructed
    _bAxes = None  # Axes for the buttons
    buttonBox_axes_list = []
    ve_list = []
    '''
    It is the list (ordered) of all the vertices and edges
    correponsding to the last CCurve.  It is necessary to the
    edge identification when erasing when replaced by a chain. 
    The position of the edge in this list coincides with the 
    position of the corresponding 2dLine element in the list 
    _axes.lines. 
 
    The list is updated when a vertex or an edge is drawn.
    But, when erasing an edge, the list and the _axes.lines 
    must be modified simultaneously.
    '''

    cidpress = None  # connection identity, an integer
    cidpress_status = False
    tmp_color = 'blue'
    img_array = None

    def __init__(self, mapFile_name):
        self.sequence = CCurvesSequence(mapFile_name, -1)
        '''
        sequence of contour curves, an object of CCurvesSequence
        The second argument is not yet known.  It will be moidified
        at the end of the initialisation.
        '''

        self.level = max(self.sequence.dic.keys())
            
        w_fig = 12.6
        h_fig = 8.2
        ## bottons position constants
        x_b = .05
        y_b = .15
        w_b = .15  # width
        h_b = .09  # height

        subplots_display = {'width_ratios': [1, 4], 'left':.05, 'right':.95,
                    'bottom':.03, 'top':.97, 'wspace':0.1}
        '''
        Extent of the subplots as a fraction of figure width or height. 
        Left cannot be larger than right, and bottom cannot be larger 
        than top.
        In fact, right = left + axes width + wspaces between axes.
        '''
        
        fig, axes = plt.subplots(1, 2, gridspec_kw=subplots_display)
        fig.set_size_inches(w_fig, h_fig)
        fig.suptitle("Press 'Draw or enrich CCurve'",
                         horizontalalignment="left", x=.02)
        axes[0].set(aspect='equal')
        axes[0].set_frame_on(False)
        axes[0].set_xlim(-1, 4)
        axes[0].set_ylim(-1, 10)
        axes[0].set_xticks([])
        axes[0].set_yticks([])

        buttonBox_axes = plt.axes([x_b, y_b, w_b, h_b])
        closeButton = Button(buttonBox_axes, "Close")
        closeButton.on_clicked(lambda x: plt.close("all"))
        self.buttonBox_axes_list.append(buttonBox_axes)
        
        buttonBox_axes = plt.axes([x_b, y_b+1.5*h_b, w_b, h_b])
        drawCurveButton = Button(buttonBox_axes, "Draw or enrich CCurve")
        drawCurveButton.on_clicked(self.callDrawCurve)
        self.buttonBox_axes_list.append(buttonBox_axes)

        buttonBox_axes = plt.axes([x_b, y_b+4.5*h_b, w_b, h_b])
        saveCCSequenceButton = Button(buttonBox_axes, "Save CC sequence")
        saveCCSequenceButton.on_clicked(self.callSaveCCSequence)
        self.buttonBox_axes_list.append(buttonBox_axes)
 
        buttonBox_axes = plt.axes([x_b, y_b+6*h_b, w_b, h_b])
        animateSequenceButton = Button(buttonBox_axes, "Animate CC sequence")
        animateSequenceButton.on_clicked(self.callAnimateCCSequence)
        self.buttonBox_axes_list.append(buttonBox_axes)

        ## main axes
        axes[1].set(aspect='equal')
        axes[1].set_frame_on(False)
        axes[1].set_xticks([])
        axes[1].set_yticks([])

        img_array = plt.imread(mapFile_name+".jpg")  # 3 dim array
        # print(np.shape(img_array)[0])
        axes[1].imshow(img_array)

        self._fig = fig
        self._bAxes = axes[0]
        self._axes = axes[1]
        self.img_array = img_array
        
        self.sequence.epsilon = max(np.shape(img_array))/(10*max(h_fig, w_fig))
        # It sets the value of epsilon for the CCurvesSequence object.
        
        plt.show()
    ### end __init__


    def callDrawCurve(self, event):
        '''
        Connects the press button event with the figure (canvas).
        The Draw curve button must be pressed for the curve to be 
        constructed or modified.
        '''
        plt.ion()
        if self.sequence.dic[0]==[]:
            title = "Draw the first CCurve; level=" + str(self.level)
        else:
            self.level = self.level + 1
            '''
            self.sequence must be modified.  The previous level curves are
            copied for the current level.  They will be modified afterwards
            through the method on_press().
            '''
            self.sequence.n_gives_nPlus1()
            title = "Enrich the CCurves; level=" + str(self.level) + "\n" \
                + "(click on a vertex to continue)"
            self.draw_previousCCurves()
            
        self._fig._suptitle.set_text(title)

        self.cidpress = self._fig.canvas.mpl_connect('button_press_event',
                                                     self.on_press)
    ### end callDrawCurve


    def on_press(self, event):
        '''
        If the "press" is in _axes, then the contour curve is constructed.
        If not, then nothing is done.
        '''
        # print('you pressed button', event.button, event.xdata, event.ydata)

        if event.inaxes==self._axes:
            x = event.xdata
            y = event.ydata
            to_draw, to_erase = self.sequence.ccs_nextEdge(x, y, self.level)
            if to_draw["vertex"]:
                self.draw_vertex(to_draw["vertex"])
            if to_draw["edge"]:
                self.draw_edge(*to_draw["edge"])
            if to_erase["vertex"]:  # a vertex
                self.erase_vertex(to_erase["vertex"])
            if to_erase["edge"]:  # a list with two edges
                for e in to_erase["edge"]:
                    self.erase_edge(e)

            self._fig.canvas.draw_idle()
        '''
        Note that plt.draw() is not the same as fig.draw() if fig is a 
        figure.  In order to draw a figure a renderer needs to be supplied.
        '''
    ### end on_press


    def callSaveCCSequence(self, event):
        plt.ion()
        self._fig._suptitle.set_text("Contour curves saved")
        if self.cidpress_status:
            self._fig.canvas.mpl_disconnect(self.cidpress)
            self.cidpress_status = False
        self.sequence.saveSequence()
        return None
    ### end callSaveCCSequence


    def draw_previousCCurves(self):
        k = max(self.sequence.dic.keys())
        for L in self.sequence.dic[k]:
            p = L[0]  # the first vertex
            for q in L[1:]:
                self.draw_edge(p, q)
                self.draw_vertex(q)
                p = q
        self._fig.canvas.draw_idle()
    ### end draw_previousCCurves
                

    def draw_vertex(self, point):
        self._axes.plot(point[0], point[1], marker='o',
                        markersiZe=4, color=self.tmp_color, ls='')
        self.ve_list.append([point])
    ### end draw_vertex

    
    def draw_edge(self, p, q):
        self._axes.plot([p[0], q[0]], [p[1], q[1]], color=self.tmp_color)
        self.ve_list.append([p, q])
    ### end draw_edge


    def erase_vertex(self, point):
        for L in self.ve_list:
            if L==[point]:
                i = self.ve_list.index(L)
                del self.ve_list[i]
                del self._axes.lines[i]
                print('vertex has been erased')
    ### end erase_vertex


    def erase_edge(self, edge):
        for L in self.ve_list:
            if set(L)==set(edge):
                i = self.ve_list.index(L)
                del self.ve_list[i]
                del self._axes.lines[i]
                print('edge has been erased')
    ### end erase_edge


    def callAnimateCCSequence(self, event):
        subplots_display = {'left':.05, 'right':.95, 'bottom':.06, 'top':.94}

        fig, axes = plt.subplots(1, 1, gridspec_kw=subplots_display)
        fig.set_size_inches(12, 8)
        axes.set(aspect='equal')
        axes.set_frame_on(True)
        axes.set_xlim(0, np.shape(self.img_array)[0])
        axes.set_ylim(-1, np.shape(self.img_array)[1])

        XX = []
        YY = []
        slides_nb = len(self.sequence.dic.keys())
        pymax = np.shape(self.img_array)[1]
        print("py max =", pymax)
        for k in self.sequence.dic.keys():
            X = []
            Y = []
            for L in self.sequence.dic[k]:
                x = [p[0] for p in L]
                y = [2*pymax-p[1] for p in L]  # horizontal flip
                X.append(x)
                Y.append(y)
            XX.append(X)
            YY.append(Y)

        def animate(i):
            for k in range(len(XX[i])):
                plt.cla()
                axes.plot(XX[i][k], YY[i][k])
                axes.set_title('Map at step ' + str(i))

        anim = FuncAnimation(fig, animate, interval=500, frames=slides_nb)
        anim.save(self.sequence.file_name + '.mp4')
        
        
    ### end callAnimateCCSequence
### end Class ContourCurves



class CCurvesSequence():
    
    xy_list = []
    '''
    It is the list of vertices of either a contour curve or of a
    chain that replace an edge in a former contour curve.
    '''

    test_vertices = []
    '''
    The first element is the index of the component in the last
    CC.  The next argument is the origin of the enriched chain;
    the next two are the vertices before and after this one in
    the former contour curve (corresponding to the above index).
    '''

    def __init__(self, file_name, epsilon):
        '''
        epsilon is needed in the almostIdentical().
        '''
        self.file_name = file_name
        self.epsilon = epsilon
        D = {}
        name = file_name + ".dat"
        if os.path.isfile(name):
            with open (name, "r") as f:
                for line in f:
                    contents = line.strip().split("&")  # type list
                    # print("text line ", contents)
                    if len(contents)==1:
                        if contents[0]!="component":
                            key = int(contents[0])
                            D[key] = [] 
                        else:
                            D[key].append([])
                    else:
                        point = (float(contents[0]), float(contents[1]))
                        D[key][-1].append(point)
        else:
             D[0] = []       
        self.dic = D
        ''' 
        The dictionary formed by the contour curves sequence; At 
        the beginning it has a single key (=0), its value being the 
        empty lilst.
        '''
    ### end __init__


    def n_gives_nPlus1(self):
        '''
        Introduces the key $n+1$ by giving it the value of the key 
        $n$ in the dictionary dic. 
        '''
        n = max(self.dic.keys())
        self.dic[n+1] = copy.deepcopy(self.dic[n])
    ### end n_gives_nPlus1    

    
    def ccs_nextEdge(self, x, y, level):
        '''
        Construct a level curve using the coordinates of each vertex
        given by an in-axes 'click' in the ComponentCurves object.  
        The click in the neighborhood of the "initial point" closes 
        the action. 
        If level = 0:
          "initial point" means "first point", and the component is 
          closed.  It uses the method next_edge().
        else:
          "initial point" means one of the three vertices: first point
          (the origin of the modification), next or previous point 
          (with respect to the initial).  
          Notice that in these later cases (next or previous), an edge 
          must be deleted in the graphical image of the ComponentCurves 
          object.  In the first case, there is either a new component 
          that is inserted, or a the initial point that is deleted.

          These operations must take place at the end of the "old edge" 
          modification.  
          It uses the method next_enrichedEdge().
        '''
        if level==0:
            return self.next_edge(x, y)  # level=0
        else:
            return self.next_enriched_edge(x, y, level)
    ### end ccs_nextEdge
    

    def next_edge(self, x, y):
        '''
        Method invoked by ccs_nextEdge().  The output is a couple: 
        to-draw (a dictionary) and to_erase (a list representing an 
        "old" edge or an "old" vertex, i.e. a list with one element).  
        In this case, to_erase is always empty.
  
        These two elements are passed to the ContourCurves object 
        through the use of ccs_nextEdge() of its attribute sequence.

        Update self.dic by calling the method ccs_update() at the end.
        '''
        self.xy_list.append((x, y))
        
        if len(self.xy_list)>1:
            q = self.xy_list[-1]
            p = self.xy_list[-2]
            
            if self.almostIdentical(self.xy_list[0], q):
                q = self.xy_list[0]
                self.xy_list[-1] = q  # the correct point in this case
                to_draw = {"vertex":None, "edge":[p, q]}                
                self.ccs_update(self.xy_list, None)
                self.xy_list = []  # a new connected component
            else:
                to_draw = {"vertex":q, "edge":[p, q]}
        else:
            to_draw = {"vertex":(x, y), "edge":None}
            
        return to_draw, {"vertex":None, "edge":[]}
    ### end next_edge


    def next_enriched_edge(self, x, y, key):
        '''
        Method invoked by ccs_nextEdge().  The output is a couple: 
        to-draw (a dictionary) and to_erase (a list representing an 
        "old" edge or an "old" vertex, i.e. a list with one element).  
        It is non-empty either when the end of the edge modification 
        is reached, i.e. the edge is replaced by the chain, or when
        the chain has the form [v, v] (clicked on the same vertex 
        twice); the vertex is erased together with the two edges 
        issued from it.

        These two elements are passed to the ContourCurves object 
        through the use of ccs_nextEdge() of its attribut sequence.

        Update self.dic by calling the method ccs_update() at the end.
        '''
        to_draw = {"vertex":None, "edge":None}
        to_erase = {"vertex":None, "edge":[]}
        if self.xy_list==[]:
            p, component_index = self.lookfor_closest_vertex((x, y), key)
            if p:
                self.xy_list.append(p)
                self.test_vertices_method(p, component_index, key)
        else:
            '''
            self.test_vertices contains the initial vertex and its
            neighborhoods.  There are four cases depending on the 
            positon of (x,y) with respect to these vertices.  When 
            (x,y) coincides with one of the self.test_vertices, then
            self.dic is updated through ccs_update().
            '''
            q = (x, y)
            cc_index = self.test_vertices[0]  # index of the CCurve
            before_v = self.test_vertices[1]
            v = self.test_vertices[2]
            after_v = self.test_vertices[3]
            status = [cc_index, v]

            # to do: clicking two times on the same point
            if self.almostIdentical(q, before_v):
                status.append("before")
                p = self.xy_list[-1]
                self.xy_list.append(before_v)
                to_draw = {"vertex":None, "edge":[p, before_v]}
                to_erase["edge"].append([before_v, v])
                self.ccs_update(self.xy_list, status)
                self.xy_list = []  # prepare a new edge modification
            elif self.almostIdentical(q, after_v):
                status.append("after") 
                p = self.xy_list[-1]
                self.xy_list.append(after_v)
                to_draw = {"vertex":None, "edge":[p, after_v]}
                to_erase["edge"].append([v, after_v])
                self.ccs_update(self.xy_list, status)
                self.xy_list = []
            elif self.almostIdentical(q, v):  # origin
                status.append("on origin") 
                '''
                There are two cases; when xy_list contains more than 
                one element, and when it is reduced to the origin.
                '''
                if len(self.xy_list)>1:
                    status.append("new component")
                    print(status)
                    p = self.xy_list[-1]
                    self.xy_list.append(v)
                    to_draw = {"vertex":None, "edge":[p, v]}
                else:
                    status.append("delete") 
                    print(status)
                    to_draw = {"vertex":None, "edge":[before_v, after_v]}
                    to_erase = {"vertex":v,
                                "edge":[[before_v, v], [v, after_v]]}
                self.ccs_update(self.xy_list, status)
                self.xy_list = []
            else:
                p = self.xy_list[-1]
                self.xy_list.append(q)
                to_draw = {"vertex":q, "edge":[p, q]}
        return to_draw, to_erase
    ### end next_enriched_edge
   
    
    def ccs_update(self, points_list, status):
        '''
        Update the self.dic dictionary using the points_list. 
        The items of self.dic are key:L, with L a list of lists.  
        Each element of L is given by a list of vertices.  There 
        might be islands!

        The behavior is different whether the maximal key is 0 or 
        not.
        
        If the maximal key is 0, then status plays no role; the 
        points_list is the list of vertices of a connected component,
        a ccurve (contour curve)

        If the maximal key is >0, then either an edge is modified or a
        vertex from a contour curve corresponding to the maximal key.
        This edge is replaced by the edges of points_list.  If a
        vertex (origin of the chain) must be modified, then... (to do)

        Desciption of status when not None; it is one of the lists
        [component_index, origin, "on origin", "new component"]
        [component_index, origin, "on origin", "delete"]
        [component_index, origin, "before"]
        [component_index, origin, "after"]
        '''
        m = max(self.dic.keys())
        if m==0:
            self.dic[m].append(points_list)
        else:
            cc_index = status[0]
            p = status[1]  # origin vertex of the chain
            cc = self.dic[m][cc_index]
            i = cc.index(p)  # index of the origin in CCurve
            if len(status)==3:
                if status[2]=="before":
                    points_list.reverse()
                    if i!=0:
                        L = cc[:i-1] + points_list + cc[i+1:]
                    else:
                        L = cc[:-2] + points_list
                else:
                    L = cc[:i] + points_list + cc[i+2:]
                self.dic[m][cc_index] = L  # replaces the edge by the chain
            else:
                '''
                Working on a vertex (the origin of the chain); the chain
                points_list is a cycle and becomes a new CCurve, or the 
                vertex is removed.  Now status has four elements.
                '''
                if status[3]=="new component":
                    self.dic[m].append(points_list)
                    # to do: moving the new origin!
                else:
                    if i==0 or i==len(cc)-1:
                        L = cc[1:-2]
                        L.append(L[0])
                    else:
                        L = cc
                        L.remove(p)
                    self.dic[m][cc_index] = L  # updates the component
                              
        return None
    ### end ccs_update


    def saveSequence(self):
        '''
        Save the sequence of CCurves in the file file_name.dat.
        '''
        name = self.file_name + ".dat"
        with open (name, "w+") as file:
            for k in self.dic.keys():
                file.write(str(k) + "\n")
                for L in self.dic[k]:
                    file.write("component\n")
                    for p in L:
                        file.write("{:.2f}".format(p[0])
                                   + " & " + "{:.2f}".format(p[1]) + "\n")
        return print("The sequence of CCurves has been saved.")
    ### emd saveSequence


    def test_vertices_method(self, vertex, component_index, key):
        '''
        Updates the test_vertices attribute.
        '''
        L = self.dic[key][component_index]
        i = L.index(vertex)
        if i==0:
            self.test_vertices = [component_index, L[-2], L[0], L[1]]
        else:
            self.test_vertices = [component_index, L[i-1], L[i], L[i+1]]
    ### end test_vertices_method
    
            
    def lookfor_closest_vertex(self, q, key):
        for L in self.dic[key]:
            for p in L:
                if self.almostIdentical(p, q):
                    return p, self.dic[key].index(L)
        return None, None
    ### end lookfor_closest_vertex


    def almostIdentical(self, point1, point2):
        '''
        Determines (boolean) if two points are sufficiently close
        to consider that they are identical.  The condition should 
        depend on the image scale, or zoom... coming from the 
        ContourCurves object.
        '''
        dx = point1[0]-point2[0]
        dy = point1[1]-point2[1]
        e = self.epsilon
        if dx<e and dx>-e and dy<e and dy>-e:
            return True
        else:
            return False
    ### end almostIdentical
### end Class CCurvesSequence

##############################################################
##############################################################

file_name = "australia"
ContourCurves(file_name)

相关内容